I've deployed a React/Express app on Heroku. I'm using BrowserRouter. Everything worked fine locally. My issue is the backend routes are not working. The only route that works is the catchall route. The catchall route is also being called three times for some reason. I console logged the request path using 'req.path' to see which path was being called. It should have been '/google'. Instead the three calls give three different logs for req.path. They are: '/static/css/main.814455d3.chunk.css.map', '/static/js/main.06bdb7f0.chunk.js.map', '/static/js/1.1baafe13.chunk.js.map'. I'm hoping someone can help.
I've been stuck for over a day now. Here are my package.json and static.json from the client side:
static.json
{
"root": "build/",
"clean_urls": false,
"routes": {
"/**": "index.html"
}
}
package.json
{
"name": "workout_tracker",
"version": "0.1.0",
"private": true,
"dependencies": {
"axios": "^0.18.0",
"jw-paginate": "^1.0.2",
"jw-react-pagination": "^1.0.7",
"normalize.css": "^8.0.0",
"query-string": "^6.2.0",
"random-id": "0.0.2",
"react": "^16.5.2",
"react-dom": "^16.5.2",
"react-headroom": "^2.2.2",
"react-icons-kit": "^1.1.6",
"react-redux": "^5.0.7",
"react-router-dom": "^4.3.1",
"react-scripts": "^2.0.5",
"react-swipe-to-delete-component": "^0.3.4",
"react-swipeout": "^1.1.1",
"redux": "^4.0.0",
"redux-thunk": "^2.3.0"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test --env=jsdom",
"eject": "react-scripts eject"
},
"devDependencies": {
"redux-devtools-extension": "^2.13.5"
},
"proxy":"localhost:4000",
"browserslist": [
">0.2%",
"not dead",
"not ie <= 11",
"not op_mini all"
]
}
And this is my package.json from express
{
"name": "expresstest",
"version": "1.0.0",
"description": "app to test express and mysql",
"main": "app.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start":"node app.js",
"heroku-postbuild": "cd client && npm install && npm run build"
},
"author": "",
"license": "ISC",
"dependencies": {
"body-parser": "^1.18.3",
"connect-flash": "^0.1.1",
"cookie-session": "^2.0.0-beta.3",
"cors": "^2.8.4",
"express": "^4.16.3",
"mysql": "^2.16.0",
"passport": "^0.4.0",
"passport-google-oauth20": "^1.0.0"
}
}
This is part of the code from the server. I omitted the other routes as none besides the catchall route are being called anyway.
let express = require("express");
let cors= require("cors");
let mysql = require("mysql");
const util = require("util");
const keys = require("./config/keys");
const passport = require("passport");
const passportSetup = require("./config/passport-setup");
const bodyParser = require("body-parser");
const flash= require("connect-flash");
const path= require("path");
console.log("process env");
console.log("-------");
console.log(process.env.PWD);
const cookieSession = require("cookie-session");
let app = express();
app.use(bodyParser.json());
app.use(cookieSession({
maxAge:24 * 60 * 60 * 1000,
keys:[keys.session.cookieKey]
}));
app.use(passport.initialize());
app.use(passport.session());
if (process.env.NODE_ENV === 'production') {
console.log("inside prod");
app.use(express.static('client/build'));
}
let connection =keys.connection;
app.get("/google", passport.authenticate("google",{
scope:['profile'],
failureFlash:"failure"
}),(req,res)=>{
// console.log(req.flash());
console.log("/google route");
});
const port = process.env.PORT || 4000;
let http = require("http");
let server = http.createServer(app,(req,res)=>{
res.writeHead(200, {"Access-Control-Allow-Origiin": "*"})
});
app.get('/*', (req, res) => {
console.log("catchall");
console.log(req.hostname);
console.log(req.path);
console.log(path.join(__dirname + '/client', 'build', 'index.html'));
res.sendFile(path.join(__dirname + '/client', 'build', 'index.html'));
})
server.listen(port, ()=>{
console.log("Listening on "+ port)
});
Here is my folder structure:
Link to pic of my folder structure
EDIT: I got it working, here is the code that works. I don't know why it works, though. I just tried some things I found on blogs for React/Express/Heroku projects. If anyone can tell me why it works it would be greatly appreciated.
let express = require("express");
let cors= require("cors");
let mysql = require("mysql");
const util = require("util");
const keys = require("./config/keys");
const passport = require("passport");
const passportSetup = require("./config/passport-setup");
const bodyParser = require("body-parser");
const flash= require("connect-flash");
const path= require("path");
console.log("process env");
console.log("-------");
console.log(process.env.PWD);
const cookieSession = require("cookie-session");
let app = express();
app.use(bodyParser.json());
app.use(express.static(__dirname));
app.use(cookieSession({
maxAge:24 * 60 * 60 * 1000,
keys:[keys.session.cookieKey]
}));
app.use(passport.initialize());
app.use(passport.session());
if (process.env.NODE_ENV === 'production') {
console.log("inside prod");
app.use(express.static('client/build'));
}
let connection =keys.connection;
app.get("/google", passport.authenticate("google",{
scope:['profile'],
failureFlash:"failure"
}),(req,res)=>{
// console.log(req.flash());
console.log("/google route");
});
const port = process.env.PORT || 4000;
let http = require("http");
let server = http.createServer(app,(req,res)=>{
res.writeHead(200, {"Access-Control-Allow-Origiin": "*"})
});
app.get("/service-worker.js", (req, res) => {
res.sendFile(path.join(__dirname + "/client","build", "service-worker.js"));
});
app.get('/*', (req, res) => {
console.log("catchall");
console.log(req.hostname);
console.log(req.path);
console.log(path.join(__dirname + '/client', 'build', 'index.html'));
res.sendFile(path.join(__dirname + '/client', 'build', 'index.html'));
})
server.listen(port, ()=>{
console.log("Listening on "+ port)
});
Related
I am trying to deploy MERN App on Vercel but getting NOT FOUND
When i put NODE_ENV as PRODUCTION then it works fine and serves the static files on local machine when run npm start but it is not working on vercel.
.
My Directory Structure is
My app.js file is
const express = require("express");
const app = express();
const dotenv = require("dotenv");
const mongoose = require("mongoose");
const PostRoutes = require("./Routes/posts");
const CategoryRoutes = require("./Routes/categories");
const UserRoutes = require("./Routes/user");
const AuthRoutes = require("./Routes/auth");
const bodyParser = require("body-parser");
const multer = require("multer");
var storage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, "uploads/images/");
},
filename: (req, file, cb) => {
cb(null, Date.now() + "_" + file.originalname);
},
});
var upload = multer({ storage: storage });
const cors = require("cors");
dotenv.config();
app.use(express.json());
app.use("uploads/images/", express.static("uploads/images/"));
app.use(bodyParser.urlencoded({ extended: true }));
app.use(cors());
if (process.env.NODE_ENV == "production") {
const path = require("path");
app.get("/", (req, res) => {
app.use(express.static(path.resolve(__dirname, "frontend", "build")));
res.sendFile(path.resolve(__dirname, "frontend", "build", "index.html"));
});
}
mongoose
.connect(process.env.MONGO_URL, {
useNewUrlParser: true,
useUnifiedTopology: true,
})
.then(console.log("connected to Mongo database "))
.catch((err) => {
console.log(err);
});
app.use("/api/posts", upload.single("photo"), PostRoutes);
app.use("/api/categories", CategoryRoutes);
app.use("/api/auth", upload.none(), AuthRoutes);
app.use("/api/users", upload.single("profile_pic"), UserRoutes);
app.listen(process.env.PORT || 3001, () => {
console.log(`Server Listening on the port ${process.env.PORT}`);
});
package.json file
{
"name": "backend",
"version": "1.0.0",
"description": "Backend to the blog app ",
"main": "app.js",
"scripts": {
"start": "node app.js",
"dev-start": "nodemon app.js --ignore client",
"start-client": "npm start --prefix frontend",
"dev": "concurrently \"cd ./frontend && npm start\" \"npm run dev-start\""
},
"author": "Shiv Shankar Prasad",
"license": "MIT",
"dependencies": {
"bcryptjs": "^2.4.3",
"body-parser": "^1.20.0",
"concurrently": "^7.4.0",
"cookie-parser": "^1.4.6",
"cors": "^2.8.5",
"dotenv": "^16.0.1",
"express": "^4.18.1",
"express-async-handler": "^1.2.0",
"express-validator": "^6.14.2",
"jsonwebtoken": "^8.5.1",
"minifaker": "^1.34.1",
"mongoose": "^6.5.3",
"multer": "^1.4.5-lts.1",
"nodemon": "^2.0.19"
}
}
Please help.
I have found a solution and it was the changes in the vercel.json file.
Now i used the vercel CLI and it is much more easy to use.
{
"version": 2,
"builds": [
{
"src": "./index.js",
"use": "#vercel/node"
}
],
"routes": [
{
"src": "/(.*)",
"dest": "/"
}
]
}
I keep getting a error "MongooseError: The uri parameter to openUri() must be a string, got "undefined". Make sure the first parameter to mongoose.connect() or mongoose.createConnection() is a string.". I've been looking at other questions that get a similar error butI did not find a solution after trying multiple different things.
in package.json
{
"dependencies": {
"bcrypt": "^5.1.0",
"body-parser": "^1.20.1",
"cors": "^2.8.5",
"dotenv": "^16.0.3",
"express": "^4.18.2",
"gridfs-stream": "^1.1.1",
"helmet": "^6.0.1",
"jsonwebtoken": "^9.0.0",
"mongoose": "^6.7.0",
"morgan": "^1.10.0",
"multer": "^1.4.4",
"multer-gridfs-storage": "^5.0.2"
},
"name": "server",
"version": "1.0.0",
"main": "index.js",
"type": "module",
"devDependencies": {},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"description": ""
}
in index.js
import express from "express";
import bodyParser from "body-parser";
import mongoose from "mongoose";
import cors from "cors";
import dotenv from "dotenv";
import multer from "multer";
import helmet from "helmet";
import morgan from "morgan";
import path from "path";
import { fileURLToPath } from "url";
/* CONFIGURATIONS */
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
dotenv.config();
const app = express();
app.use(express.json());
app.use(helmet());
app.use(helmet.crossOriginResourcePolicy({ policy: "cross-origin" }));
app.use(morgan("common"));
app.use(bodyParser.json({ limit: "30mb", extended: true }));
app.use(bodyParser.urlencoded({ limit: "30mb", extended: true }));
app.use(cors());
app.use("/assets", express.static(path.join(__dirname, "public/assets")));
/* FILE STORAGE */
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, "public/assets");
},
filename: function (req, file, cb) {
cb(null, file.originalname);
},
});
const upload = multer({ storage });
/* MONGOOSE SETUP */
const PORT = process.env.PORT || 6001;
mongoose
.connect(process.env.MONGO_URL, {
useNewUrlParser: true,
useUnifiedTopology: true,
})
.then(() => {
app.listen(PORT, () => console.log(`Server Port: ${PORT}`));
})
.catch((error) => console.log(`${error} did not connect`));
in .env
MONGO_URL = 'the connection string'
PORT = 3001
The homepage loads ok in my ReactJSAPP, but when I click on any link it throws the following error. Since I am new to ReactJS, I am not sure which file I should check and fix this issue. Nodejs is working on port 4407
Folder Structure
Not Found
404
Error: Not Found
at /home/abc/public_html/ReactNode/app.js:46:13
at Layer.handle [as handle_request] (/home/abc/public_html/ReactNodeNew/node_modules/express/lib/router/layer.js:95:5)
Index.js
var express = require('express');
var router = express.Router();
/* GET home page. */
router.get('/', function(req, res, next) {
res.render('index', { title: 'Express' });
});
module.exports = router;
My package.json is
{
"name": "frontend",
"version": "0.1.0",
"private": true,
"dependencies": {
"bootstrap": "^4.3.1",
"fixed-data-table": "^0.6.4",
"font-awesome": "^4.7.0",
"mysql": "^2.14.1",
"react": "^16.8.6",
"react-bootstrap": "^0.31.5",
"react-dom": "^16.8.6",
"react-redux": "^5.0.6",
"react-router": "^3.0.0",
"react-scripts": "3.0.0",
"redux": "^3.7.2"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"proxy": "http://localhost:4007",
"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"
]
}
}
And app.js
var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var index = require('./routes/index');
var users = require('./routes/users');
var app = express();
const port = process.env.PORT || 4007;
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
var mysql = require("mysql");
//Database connection
app.use(function(req, res, next){
res.locals.connection = mysql.createConnection({
host : '127.0.0.1',
user : 'nodejs',
password : '333365,',
database : 'nodejs',
port : '3306'
});
res.locals.connection.connect();
next();
});
// uncomment after placing your favicon in /public
//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'frontend/build')));
app.use('/api', index);
app.use('/api/users', users);
// catch 404 and forward to error handler
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
// error handler
app.use(function(err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.render('error');
});
app.get('*', (req, res) => {
res.sendFile(path.join(__dirname + '/frontend/build/index.html'))
})
var http = require('http');
module.exports = app;
var server = http.createServer(app);
server.listen(port);
I get the following error when using a express-react app on docker.
i referred to this
React Proxy error: Could not proxy request /api/ from localhost:3000 to http://localhost:8000 (ECONNREFUSED)
and the solution doesn't seem to work.
setupProxy.js
const proxy = require('http-proxy-middleware');
module.exports = function(app) {
app.use(proxy('/auth/github', { target: 'http://[::1]:5000/' }))
app.use(proxy('/api/users/auth/github', { target: 'http://[::1]:5000/' }))
app.use(proxy('/api/users/', { target: 'http://[::1]:5000/', "secure": false }))
app.use(proxy('/api/posts/', { target: 'http://[::1]:5000/' }))
}
Dockerfile
FROM node:8.10.0-alpine
EXPOSE 5000
COPY . /home/app
WORKDIR /home/app
RUN npm install
CMD ["npm", "start"]
docker-compose.yml
# docker-compose.yml
version: "3"
services:
app:
build: .
restart: always
depends_on:
- postgres
ports:
- 5000:3000
postgres:
image: postgres:9.6.8-alpine
expose:
- 5432
environment:
POSTGRES_PASSWORD: postgres
POSTGRES_USER: user
POSTGRES_DB: db
Package.json
{
"name": "sequelize-demo",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"client": "cd ./client && npm start ",
"server": "nodemon app.js --ignore client",
"build": "echo 'hello build'",
"start": "concurrently --kill-others \"npm run server\" \"npm run client\""
},
"author": "",
"license": "ISC",
"dependencies": {
"async": "^2.6.1",
"bcrypt": "^3.0.3",
"body-parser": "^1.18.3",
"concurrently": "^4.1.0",
"cookie-parser": "^1.4.3",
"cookie-session": "^2.0.0-beta.3",
"cors": "^2.8.5",
"crypto": "^1.0.1",
"dotenv": "^6.2.0",
"express": "^4.16.4",
"express-flash": "0.0.2",
"express-session": "^1.15.6",
"jsonwebtoken": "^8.4.0",
"morgan": "^1.9.1",
"nodemailer": "^5.1.1",
"nodemon": "^1.18.9",
"passport": "^0.4.0",
"passport-github": "^1.1.0",
"passport-github2": "^0.1.11",
"passport-jwt": "^4.0.0",
"passport-local": "^1.0.0",
"pg": "^7.8.0",
"pg-hstore": "^2.3.2",
"sequelize": "^4.42.0"
}
}
app.js
var express = require('express');
var app = express();
var userRoute = require('./routes/users');
var postRoute = require('./routes/posts');
var bodyParser = require('body-parser');
var logger = require('morgan');
var models = require('./models');
var User = require('./models/user');
var session = require('express-session');
var cookieParser = require('cookie-parser') ;
var cookieSession = require('cookie-session');
var dotenv = require('dotenv');
var env = dotenv.config();
var cors = require('cors');
const port = process.env.PORT || 5000;
const passport = require('passport');
const path = require('path');
// CORS Middleware
app.use(cors());
app.use(logger('dev'));
app.use(express.static(path.join(__dirname, 'public')));
app.use(cookieParser());
app.use(bodyParser());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(session({
secret : 'nodeauthsecret',
resave: false,
saveUninitialized: true,
}));
app.use(passport.initialize());
app.use(passport.session());
require('./config/passport')(passport);
require('./config/passport-github')(passport);
app.use(function(req, res, next) {
res.locals.user = req.user; // This is the important line
console.log(res.locals.user);
next();
});
// app.use(function(req, res, next) {
// res.setHeader("Access-Control-Allow-Origin", "*");
// res.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
// });
app.use('/api/users', userRoute )
app.use('/api/posts', postRoute )
app.listen(port, function() {
console.log(`Server is running on ${port}`);
});
Let's make sense of this:
The API server listens for requests on default port of 5000 in the docker container.
The API service is composed using docker-compose to publish port 5000 in the node machine for target port 3000 in the container.
Then, the client server is set up to proxy API requests to port 5000 in the node machine.
Clearly, there isn't any service running on 3000 in the container.
You can correct the target port by setting it to 5000 in docker-compose.yaml
ports:
- 5000:5000
I have already run my nodejs app successfully on my localhost, but when I deploy it on heroku, build success, but I got a "Application Error", when I use "heroku logs", it show like this:
console screenshot
I can't figure out what's wrong with my app, hope to get your help, thanks!
Here's my package.json
{
"main": "index.js",
"scripts": {
"test": "mocha --harmony test",
"start": "cross-env NODE_ENV=production pm2 start index.js --node-args='--harmony' --name 'adolt-blog'"
},
...
"dependencies": {
"config-lite": "^1.5.0",
"connect-flash": "^0.1.1",
"connect-mongo": "^1.3.2",
"cross-env": "^3.1.3",
"ejs": "^2.5.2",
"express": "^4.14.0",
"express-formidable": "^1.0.0",
"express-session": "^1.14.2",
"express-winston": "^2.0.0",
"marked": "^0.3.6",
"moment": "^2.17.0",
"mongolass": "^2.3.2",
"objectid-to-timestamp": "^1.3.0",
"sha1": "^1.1.1",
"winston": "^2.3.0",
"pm2": "^2.2.3",
"mocha": "^3.2.0"
}
}
and index.js
var path = require('path');
var express = require('express');
var session = require('express-session');
var MongoStore = require('connect-mongo')(session);
var flash = require('connect-flash');
var config = require('config-lite');
var routes = require('./routes');
var pkg = require('./package');
var winston = require('winston');
var expressWinston = require('express-winston');
var app = express();
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
app.use(express.static(path.join(__dirname, 'public')));
app.use(session({
name: config.session.key,
secret: config.session.secret,
cookie: {
maxAge: config.session.maxAge
},
store: new MongoStore({
url: config.mongodb
}),
saveUninitializedSession: true,
resaveSession: true
}));
app.use(flash());
app.use(require('express-formidable')({
uploadDir: path.join(__dirname, 'public/img'),
keepExtensions: true
}));
app.locals.blog = {
// title: pkg.name,
// description: pkg.description
title: 'Adolt\'s Blog',
description: 'Learn Node.js'
};
app.use(function (req, res, next) {
res.locals.user = req.session.user;
res.locals.success = req.flash('success').toString();
res.locals.error = req.flash('error').toString();
next();
});
app.use(expressWinston.logger({
transports: [
new (winston.transports.Console)({
json: true,
colorize: true
}),
new winston.transports.File({
filename: 'logs/success.log'
})
]
}));
routes(app);
app.use(expressWinston.errorLogger({
transports: [
new winston.transports.Console({
json: true,
colorize: true
}),
new winston.transports.File({
filename: 'logs/error.log'
})
]
}));
if (module.parent) {
module.exports = app;
} else {
const port = process.env.PORT;
app.listen(port, function () {
console.log(`${pkg.name} listening on port ${port}`);
});
}
Thanks to the help of #Lucas Katayama, the problem finally solved.
First, add main.js according to the use-pm2-with-cloud-providers.
And then modify the Procfile like this
web: node main.js
Finally, rebuild your app and see if it works!
Hope it can help! Good luck!