Heroku is ignoring my .env file for some reason, even though express shows what port to use and etc. I'm getting this error
Web process failed to bind to $PORT within 60 seconds
I read other solutions that talk about removing dotenv but if i do that, it will crash my app. I would need dotenv to get env variables, is there way i can set an .env for heroku or what would be the best solution to deploy a express + react + postgress application on heroku ?
here is my Profile
web: node app.js
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 session = require('express-session');
var cookieParser = require('cookie-parser') ;
var dotenv = require('dotenv');
var env = dotenv.config();
var cors = require('cors');
var models = require('./models/');
const PORT = process.env.PORT || 8000;
const passport = require('passport');
const path = require('path');
// const allowOrigin = process.env.ALLOW_ORIGIN || '*'
// CORS Middleware
if (!process.env.PORT) {
require('dotenv').config()
}
// console.log(process.env.DATABASE_URL);
if (!process.env.PORT) {
console.log('[api][port] 8000 set as default')
console.log('[api][header] Access-Control-Allow-Origin: * set as default')
} else {
console.log('[api][node] Loaded ENV vars from .env file')
console.log(`[api][port] ${process.env.PORT}`)
console.log(`[api][header] Access-Control-Allow-Origin: ${process.env.ALLOW_ORIGIN}`)
}
require('./config/passport-github');
require('./config/passport');
app.use(logger('dev'));
app.use(express.static(path.join(__dirname, 'public')));
app.use(express.static(path.join(__dirname, 'build')));
app.use(cookieParser());
app.use(session({
secret : process.env.JWT_SECRET,
saveUninitialized: false,
maxAge: 1000 * 60 * 60 * 84,
resave: false
}));
app.use(passport.initialize());
app.use(passport.session());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended:false}));
const isAuthenticated = function(req, res, next){
if(req.isAuthenticated()){
next();
console.log('this works');
}else{
res.redirect('http://127.0.0.1:8001/signIn');
}
}
// app.use(function(req, res, next) {
// res.header('Access-Control-Allow-Origin', '*');
// // res.header('Access-Control-Allow-Credentials', true);
// res.header("preflightContinue", false)
// // res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
// res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization');
// next();
// });
app.use(cors({
'allowedHeaders': ['Content-Type'], // headers that React is sending to the API
'exposedHeaders': ['Content-Type'], // headers that you are sending back to React
'origin': '*',
'methods': 'GET,HEAD,PUT,PATCH,POST,DELETE',
'preflightContinue': false
}));
app.use('/api/users', userRoute );
app.use('/api/posts', isAuthenticated, postRoute );
app.use(function(req, res, next) {
res.locals.user = req.user; // This is the important line
// req.session.user = user
console.log(res.locals.user);
next();
});
models.sequelize.sync().then(() => {
const server = app.listen(PORT, () => {
console.log(`Server is up and running on port ${PORT}`);
});
});
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",
"start": "concurrently --kill-others \"npm run client\" \"npm run server\" ",
"heroku-postbuild": "cd client && npm install && npm run build"
},
"author": "",
"license": "ISC",
"dependencies": {
"async": "^2.6.1",
"bcrypt": "^3.0.2",
"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": "^7.0.0",
"express": "^4.16.4",
"express-flash": "0.0.2",
"express-session": "^1.15.6",
"foreman": "^3.0.1",
"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"
},
"devDependencies": {
"chai": "^4.2.0",
"mocha": "^6.1.2"
}
}
config/database.js
if (!process.env.PG_DB) {
const fs = require('fs')
const dotenv = require('dotenv')
const envConfig = dotenv.config({silent: true})
// for (var k in envConfig) {
// process.env[k] = envConfig[k]
// }
console.log('[api][sequelize] Loaded database ENV vars from .env file')
}
module.exports = {
development: {
username: process.env.POSTGRES_USER,
password: process.env.POSTGRES_PASSWORD,
database: process.env.POSTGRES_DB,
host: process.env.POSTGRES_HOST,
dialect: 'postgres',
migrationStorageTableName: 'sequelize_meta'
},
production: {
username: "root",
password: null,
database: "*******",
host: "127.0.0.1",
dialect: "postgres"
}
}
config/config.json
{
"development": {
"username": "eli",
"password": "",
"database": "elitest4",
"host": "127.0.0.1",
"dialect": "postgres"
},
"test": {
"username": "root",
"password": null,
"database": "database_test",
"host": "127.0.0.1",
"dialect": "postgres"
},
"production": {
"username": "root",
"password": null,
"database": "*******",
"host": "127.0.0.1",
"dialect": "postgres"
}
}
client/package.json
{
"name": "client",
"version": "0.1.0",
"private": true,
"dependencies": {
"#material-ui/core": "^3.9.1",
"#material-ui/icons": "^3.0.2",
"axios": "^0.18.0",
"history": "^4.7.2",
"http-proxy-middleware": "^0.19.1",
"jsonwebtoken": "^8.4.0",
"jwt-decode": "^2.2.0",
"material-ui-icons": "^1.0.0-beta.36",
"moment": "^2.24.0",
"react": "^16.7.0",
"react-dom": "^16.7.0",
"react-redux": "^6.0.0",
"react-router-dom": "^4.3.1",
"react-scripts": "2.1.3",
"redux": "^4.0.1",
"redux-thunk": "^2.3.0",
"superagent": "^4.1.0"
},
"scripts": {
"start": "PORT=8001 react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject",
"postinstall": "react-scripts build"
},
"eslintConfig": {
"extends": "react-app"
},
"browserslist": [
">0.2%",
"not dead",
"not ie <= 11",
"not op_mini all"
],
"devDependencies": {
"dotenv": "^6.2.0"
}
}
This is a simple oversight when deploying to Heroku. Heroku manages its own env vars to keep them safe. You should not be committing your .env to git or any version control. In Heorkus case simply go to the apps dashboard, in the settings tab and click reveal config vars and put the content of your dot env in the ui.
You can use the link bellow put your app name in there and you should see the settings screen.
https://dashboard.heroku.com/apps/<your_app_name>/settings
Related
I am trying to make a post request using fetch. Normally when I use npm start to start my server it works just fine. But with webpack dev server it gives me this error:
This is my server side code:
require('dotenv').config();
const mockAPIResponse = require('./mockAPI.js')
const PORT = 8081
const apiKey = process.env.API_KEY
const baseUrl = 'https://api.meaningcloud.com/sentiment-2.1'
const express = require('express')
const cors = require('cors')
const bodyParser = require('body-parser')
const fetch = require('node-fetch')
var path = require('path')
const app = express();
app.use(cors())
app.use(bodyParser.json())
app.use(bodyParser.urlencoded({ extended: false }))
app.use(express.static('dist'))
app.get('/', function(req, res) {
res.sendFile('dist/index.html')
//res.sendFile(path.resolve('src/client/views/index.html'))
})
app.post('/api', async(req, res) => {
console.log("you key is", apiKey)
const enteredUrl = req.body.url;
const apiUrl = baseUrl + '?key=' + apiKey + '&url=' + enteredUrl + '&lang=en'
console.log(apiUrl)
const response = await fetch(apiUrl)
try {
const fetchedData = await response.json()
console.log(fetchedData)
res.send(fetchedData)
} catch (error) {
console.log("error", error)
}
})
app.get('/test', function(req, res) {
res.send(mockAPIResponse)
})
// designates what port the app will listen to for incoming requests
app.listen(PORT, (error) => {
if (error) throw new Error(error)
console.log(`Server listening on port ${PORT}!`)
})
My package.json:
{
"name": "evaluate-news-nlp",
"version": "0.0.1",
"main": "index.js",
"scripts": {
"test": "jest",
"start": "nodemon src/server/index.js",
"build-prod": "webpack --config webpack.prod.js",
"build-dev": "webpack-dev-server --config webpack.dev.js --open"
},
"keywords": [],
"author": "Alaa",
"description": "",
"dependencies": {
"2": "^3.0.0",
"#babel/runtime": "^7.16.7",
"axios": "^0.21.1",
"babel-polyfill": "^6.26.0",
"body-parser": "^1.19.0",
"cors": "^2.8.5",
"dotenv": "^8.6.0",
"express": "^4.17.1",
"node-fetch": "^2.6.1",
"sass": "^1.45.1",
"webpack": "^4.44.2",
"webpack-cli": "^3.3.5"
},
"devDependencies": {
"#babel/core": "^7.5.4",
"#babel/plugin-transform-runtime": "^7.16.7",
"#babel/preset-env": "^7.5.4",
"#types/jest": "^26.0.20",
"babel-core": "^6.26.3",
"babel-loader": "^8.0.6",
"babel-plugin-transform-runtime": "^6.23.0",
"babel-polyfill": "^6.26.0",
"babel-preset-es2015": "^6.24.1",
"babel-preset-stage-0": "^6.24.1",
"clean-webpack-plugin": "^3.0.0",
"css-loader": "^5.1.2",
"file-loader": "^6.1.1",
"html-webpack-plugin": "^3.2.0",
"jest": "^26.5.3",
"mini-css-extract-plugin": "^0.9.0",
"nodemon": "^2.0.7",
"optimize-css-assets-webpack-plugin": "^5.0.4",
"prettier": "^2.2.1",
"sass": "^1.45.2",
"sass-loader": "^10.1.1",
"style-loader": "^2.0.0",
"supertest": "6.1.3",
"terser-webpack-plugin": "^1.4.5",
"webpack-dev-server": "^3.7.2",
"workbox-webpack-plugin": "^6.1.1"
}
}
Webpack dev server works fine until I try to make the post request. I tried different versions of webpacks, webpack dev server, node-fetch but still getting the same error.
How can I solve this error?
Edit: I think the problem has something to do with the fact that webpack dev server runs on port 8080 while my express server runs on 8081. When I checked the network tab for the request this is what's shown:
And this shows up after the error:
Edit: I was able to solve the problem by running webpack dev server and then opening another terminal and running npm start to start my express server. Is this how it's supposed to work normally? Because the tutorial I was following was working fine with only webpack dev server
This error happens because the express server isn't running. Run npm start to start the express server
i have a problem, which when im trying to run my localhost/5000 its not working. I cant also get and post data on postman because of that. Anyone has an idea of how i can fix this ? However when i run the code it is showing that it is connected to my DB. I have also create an env file with the DB link and set the PORT to 5000
Here is the code:
server.js
const express = require('express')
const mongoose = require('mongoose')
const cors = require('cors')
const fileUpload = require('express-fileupload')
const cookieParser = require('cookie-parser')
const PORT = process.env.PORT || 5000
const app = express();
app.use(express.json())
app.use(cookieParser())
app.use(cors)
app.use(fileUpload({
useTempFiles: true
}))
//connect to db
const URI = process.env.MONGO_URL
mongoose.connect(URI,{
useCreateIndex: true,
useFindAndModify: false,
useNewUrlParser:true,
useUnifiedTopology:true
}, err=> {
if (err) throw err;
console.log('Connected to Mongo DB')
})
// app.get('/', (req, res) => {
// res.json({msg: "Welcome"})
// })
app.listen(PORT, () => {
console.log('Server is running on port', PORT)
})
app.use('/user', require('./routes/userRouter'))
package.json
{
"name": "Webapp",
"version": "1.0.0",
"description": "",
"main": "server.js",
"scripts": {
"dev": "nodemon server.js"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"bcrypt": "^5.0.0",
"cloudinary": "^1.23.0",
"concurrently": "^5.3.0",
"cookie-parser": "^1.4.5",
"cors": "^2.8.5",
"dotenv": "^8.2.0",
"express": "^4.17.1",
"express-fileupload": "^1.2.1",
"jsonwebtoken": "^8.5.1",
"mongoose": "^5.11.12"
},
"devDependencies": {
"nodemon": "^2.0.7"
}
}
app.listen() should be at end of file, after app.use()
Just use localhost:5000 instead of localhost/5000 for url
In Development mode, react and express get connected perfectly and I am able to fetch data from backend. But, when using them in production mode, I am getting a status of 200 but unable to get the json response from express.
I am getting this error:
SyntaxError: JSON.parse: unexpected character at line 1 column 1 of the JSON data
Backend File is this:
const express = require('express');
const bodyParser = require("body-parser");
const cors = require("cors");
const path = require("path");
const helmet = require("helmet");
const compression = require("compression");
if(process.env.NODE_ENV !== "production") require('dotenv').config();
const app = express();
//middlewares
app.use(helmet());
app.use(compression());
app.use(cors());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
// serve the react app files in production
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"))
})
}
//port
const port = process.env.PORT || 5000;
app.listen(port, error => {
if(error) throw error;
console.log(`Backend is running on localhost:${port}`);
});
// connection route
app.get("/express", (req, res) => res.json({express: "YOUR EXPRESS BACKEND IS CONNECTED"}));
Backend package.json:
{
"name": "",
"version": "1.0.0",
"description": "",
"main": "server.js",
"engines": {
"node": "12.19.0",
"npm": "6.14.8"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "nodemon server.js",
"mainstart": "concurrently --kill-others-on-fail \"npm start\" \"cd client && yarn start\""
},
"repository": {
"type": "git",
"url": "git+https://github.com/g4rry420/armourLine.git"
},
"author": "Gurkiran Singh",
"license": "ISC",
"bugs": {
"url": ""
},
"homepage": "",
"dependencies": {
"body-parser": "^1.19.0",
"compression": "^1.7.4",
"concurrently": "^5.3.0",
"cors": "^2.8.5",
"dotenv": "^8.2.0",
"express": "^4.17.1",
"helmet": "^4.2.0",
"nodemon": "^2.0.6",
"path": "^0.12.7"
}
}
Front end App.js
import React,{ useEffect, useState } from 'react';
import { Route, Switch } from "react-router-dom"
import './App.css';
import Header from "./components/header/header.component"
import ProductItem from './components/product-item/product-item.component';
import Homepage from './pages/homepage.component';
import ProductForm from "./components/product-form/product-form.component";
function App() {
const [backendData, setBackendData] = useState("No Fetching")
useEffect(() => {
callBackedApi()
.then(res => setBackendData(res.express))
.catch(err => console.log(err))
}, [])
async function callBackedApi(){
const response = await fetch("/express", {
headers: {
'Content-Type': 'application/json',
},
})
const body = await response.json();
if(response.status !== 200){
throw Error(body.message)
}
return body;
}
return (
<div className="App">
{backendData}
<Header />
<div>
<Switch>
<Route exact path="/" component={Homepage} />
<Route path="/product" component={ProductItem} />
<Route path="/product-form" component={ProductForm} />
</Switch>
</div>
</div>
);
}
export default App;
Frontend package.json
{
"name": "armourline",
"version": "0.1.0",
"private": true,
"proxy": "http://localhost:5000",
"dependencies": {
"#testing-library/jest-dom": "^4.2.4",
"#testing-library/react": "^9.3.2",
"#testing-library/user-event": "^7.1.2",
"bootstrap": "^4.5.2",
"react": "^16.13.1",
"react-bootstrap": "^1.3.0",
"react-dom": "^16.13.1",
"react-icons": "^3.11.0",
"react-router-dom": "^5.2.0",
"react-scripts": "3.4.3",
"react-slick": "^0.27.13"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"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"
]
}
}
You have a route ordering problem.
In production, you have this code active:
// serve the react app files in production
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"))
})
}
Which puts the app.get("*", ...) route BEFORE your app.get("/express", ...) route so the * route will grab the request and send it HTML which won't parse as JSON. The order of your routes matters when they can conflict.
Move your app.get("/express", ...) route BEFORE your app.get("*", ...) route, In fact, the * route should probably be last so all individually specified routes get a chance to grab the request before the * route does. Personally I don't use * routes myself because of some of the issues they can cause.
So I got things working where it babel compiles everything, including next.js
I followed next.js docs on how to handle babel and created a .babelrc file:
{
"presets": ["next/babel", "es2015", "stage-0"]
}
When I run yarn run dev everything compiles and the server starts. When I load a page, next.js will run it's build process. Since things in the directory change, nodemon restarts the server and causes an infinite loop. Can some help me with this please???
This is my package.json file:
{
"name": "creatorsneverdie",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"scripts": {
"dev": "nodemon app.js --exec babel-node --ignore node_modules, .next, yarn.lock",
"build": "next build",
"start": "NODE_ENV=production node app.js"
},
"dependencies": {
"axios": "^0.16.2",
"bcrypt": "^1.0.2",
"body-parser": "^1.17.2",
"cors": "^2.8.4",
"cryptr": "^2.0.0",
"dotenv": "^4.0.0",
"express": "^4.15.3",
"express-session": "^1.15.4",
"lodash": "^4.17.4",
"lowdb": "^0.16.2",
"next": "^2.4.7",
"passport": "^0.3.2",
"passport-jwt": "^2.2.1",
"react": "^15.6.1",
"react-dom": "^15.6.1"
},
"devDependencies": {
"babel-cli": "^6.24.1",
"babel-loader": "^7.1.1",
"babel-preset-es2015": "^6.24.1",
"babel-preset-stage-0": "^6.24.1",
"nodemon": "^1.11.0"
}
}
And the app.js file:
import express from 'express'
import session from 'express-session'
import bodyParser from 'body-parser'
import cors from 'cors'
import passport from 'passport'
const db = require('./db/index.js').initDb()
const writeSeeds = require('./db/index.js').writeSeeds
const routes = require('./routes/index')
require('dotenv').config({path: 'variables.env'});
// Next config
const next = require('next')
const dev = process.env.NODE_ENV !== 'production'
const nextLoader = next({dev})
const handle = nextLoader.getRequestHandler()
nextLoader.prepare().then(() => {
const app = express();
app.use(cors());
app.set('db', db);
app.nextRender = nextLoader
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: true}));
app.use(session({
secret: process.env.SECRET,
resave: false,
saveUninitialized: false
}));
app.use(passport.initialize());
app.use(passport.session());
require('./config/passport')(passport);
app.use('/', routes)
app.get('*', (req, res) => {
return handle(req, res)
})
// START APP
app.set('port', process.env.PORT || 1337);
if(!db.has('products').value()) {
writeSeeds(db);
}
const server = app.listen(app.get('port'), () => {
console.log(`Express running -> ${server.address().port}`)
});
})
I was having the same problem and I fixed that by adding "pages/"* to nodemon's ignore list. Somehow the build process is doing the pages source rewrite without changing anything which is then causing nodemon to restart and triggers the rebuild again.
Try to change your dev script to:
nodemon -w app.js --exec babel-node
I built a small app on top of a company's API. I created my own API to interact with their's. My app uses React-Create-App to scaffold, with Redux, and the server is Experss/Node.js. It works totally fine on localhost but when I deploy it on Heroku, it serves the bundle but doesn't hand any user http requests to the server. It returns a 404 not found. Heroku gives no errors in their logs.
My post install script runs the build, which bundles the app. I have set environment port variable in the heroku dashboard as well.
package.json
{
"name": "event.me",
"version": "0.1.0",
"private": true,
"engines":{
"node": "7.2.1",
"npm": "3.10.10"
},
"dependencies": {
"axios": "^0.15.3",
"body-parser": "^1.17.1",
"express": "^4.15.2",
"moment": "^2.18.1",
"react": "^15.4.2",
"react-dom": "^15.4.2",
"react-progressbar.js": "^0.2.0",
"react-redux": "^5.0.3",
"react-router": "^3.0.0",
"react-router-dom": "^4.0.0",
"redux": "^3.6.0",
"redux-logger": "^3.0.0",
"redux-thunk": "^2.2.0"
},
"devDependencies": {
"eslint": "^3.18.0",
"eslint-config-airbnb": "^14.1.0",
"eslint-plugin-jsx-a11y": "^4.0.0",
"eslint-plugin-react": "^6.9.0",
"eslint-plugin-import": "^2.2.0",
"nodemon": "^1.11.0",
"react-scripts": "0.9.5"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test --env=jsdom",
"eject": "react-scripts eject",
"server": "node server/server.js",
"postinstall": "npm run build"
}
}
server.js file
const express = require('express');
const path = require('path');
const bodyParser = require('body-parser');
const routes = require('./routes');
const app = express();
app.use(express.static(path.resolve(__dirname, '..', 'build')));
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
app.use('/api', routes);
const port = process.env.PORT || 8080;
app.listen(port, () => console.log(`Listening on ${port}`));
routes.js
const routes = require('express').Router();
const users = require('./controllers/users.js');
const events = require('./controllers/events.js');
routes.post('/sigin', users.signin);
routes.post('/signup', users.signup);
routes.get('/events', events.getAll);
routes.post('/events', events.attendEvent);
routes.delete('/events', events.flakeEvent);
routes.patch('/events', events.updateEvent);
routes.delete('/singleevent', events.deleteEvent);
routes.post('/createevent', events.createEvent);
module.exports = routes;
If you are using Create React App, one of the things you must do if you want Webpack to be used as proxy when calling your API is to set in your package.json:
...
"proxy": "http://localhost:3030",
...
Thus you use Webpack included in Create React App to proxy all the calls to your API and do not need an extra server.
For Heroku deployment you need to change localhost for Heroku URL and 3030 for your established port in Express server (process.env.PORT).
That's where I think the problem lies.
Also, you have to route your non API petitions to your index.html.
Add this to your server.js.
app.get('*', (req, res) => {
const way = path.join(__dirname, 'build', 'index.html');
res.sendFile(way);
});