I'm developing a blog application with firebase. I'm using express with ejs on this project.
PROBLEM - The project is working perfectly when I run them using the emulator, but doesn't work on firebase's hosting.
I've tried changing my code and re-deploying all the files many times. The function is visible in the 'functions' tab in firebase, and doesn't log any errors when I open the page.
I've checked the following ->
1) Firebase functions SDK, npm modules, and the CLI updated to the latest version.
// >>package.json<<
{
"name": "functions",
"description": "Cloud Functions for Firebase",
"scripts": {
"serve": "firebase emulators:start --only functions",
"shell": "firebase functions:shell",
"start": "npm run shell",
"deploy": "firebase deploy --only functions",
"logs": "firebase functions:log"
},
"engines": {
"node": "10"
},
"dependencies": {
"ejs": "^3.1.3",
"express": "^4.17.1",
"firebase-admin": "^8.10.0",
"firebase-functions": "^3.7.0"
},
"devDependencies": {
"firebase-functions-test": "^0.2.0"
},
"private": true
}
2) The project is running on node 10.
3) I've added rewrites to my function in firebase.json
//>>firebase.json<<
"firestore": {
"rules": "firestore.rules",
"indexes": "firestore.indexes.json"
},
"hosting": {
"public": "public",
"ignore": [
"firebase.json",
"**/.*",
"**/node_modules/**"
],
"rewrites": [ {
"source": "**",
"function": "app"
} ]
},
4) Tried the Port Numbers, and cross-checked other essential configurations.
5) My project is linked to google cloud, which has an active payment account.
6) Works fine when tested locally in a firebase emulator.
This is my function
// >>index.js<<
const functions = require('firebase-functions');
const express = require('express');
const app = express(); // express initialize
//firestore
const admin = require('firebase-admin');
admin.initializeApp();
const db = admin.firestore();
app.listen(443); // listen for requests
// register view engine
app.set('view engine', 'ejs');
app.set('views', './views');
// middleware & static files
app.use(express.static('stats'));
// HANDLING REQUESTS
app.get('/', (req, res) => {
res.render('index', { title: "Blog by Zeal For Good" });
})
app.get('/index', (req, res) => {
res.redirect('/');
})
app.use((req, res) => {
res.status(404).render('404', { title: '404' });
});
exports.app = functions.https.onRequest(app);
I'm getting this message when I'm opening my website (https://zealforgood-blog.web.app/) ->
Install Express on 'functions' folder.
Install all modules that you need of the ExpressJs on 'functions' folder.
The Firebase with Cloud Functions need 'Cors' module running in ExpressJs. Install it.
The System needs a 'public' folder on project's base folder, another 'public' folder on the 'functions' folder.
After, run 'npm install' in project's base folder and on the 'fuctions' folder
delete 'index.html' and '404.html' on the 'public' folders genereted for Default by Firebase
change your files .html to .ejs;
Adjust your project like this:
// in firebase.json use: //
"source": "/**",
// in index.js: //
const cors = require('cors');
...
const app = express();
...
// set view engine setup EJS
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
// set this line below too
app.engine('ejs', require('ejs').__express);
app.use(cors({ origin: true }));
Note: This line below is a copy from the japanese site that do EJS render on Cloud Functions (https://qiita.com/kingpanda/items/aa9bdef2706857720058).
app.engine('ejs', require('ejs').__express);
Works to me!
Good Luck!
Related
Trying to make my first Vue application, simple game with MEVN stack. Working perfect interacting with backend on development environment, however when hosting it doesn't fetch the data from the server.
Anyone able to point out what I have incorrect with the below?
More info below:
File structure:
/root
|- config.js
|- server.js
|- package.json + package-lock.json
|- client/
|- vue.config.json
|- ... (rest of dist, src, node_modules, public etc.)
|- models/
|- Elf.js + HighScore.js
|- routes/
|- api/
|- elf.js + highScore.js
config.js
module.exports = {
hostUrl: process.env.HOST_URL,
mongoURI: process.env.MONGO_URI,
PORT: process.env.PORT || 3000,
};
server.js
const express = require("express");
const app = express();
const port = 3000;
const mongoose = require("mongoose");
const { PORT, mongoURI } = require("./config.js");
// routes
const Player = require("./routes/api/player");
const Elf = require("./routes/api/elf");
const HighScore = require("./routes/api/highScore");
// cors is a middleware that allows us to make requests from our frontend to our backend
const cors = require("cors");
// morgan is a middleware that logs all requests to the console
const morgan = require("morgan");
// body-parser is a middleware that allows us to access the body of a request
const bodyParser = require("body-parser");
const path = require("path");
app.use(cors());
// use tiny to log only the request method and the status code
app.use(morgan("tiny"));
app.use(bodyParser.json());
// chek if we are in production
if (process.env.NODE_ENV === "production") {
// check if we are in production mode
app.use(express.static("client/dist"));
app.get("*", (req, res) => {
res.sendFile(path.resolve(__dirname, "client", "dist", "index.html"));
});
}
// test if server is running and connected to mongoDB
app.get("/", (req, res) => {
res.send("Hello World!");
});
// app.get("/", (req, res) => {
// res.send("Hello World!");
// });
// use routes
app.use("/api/", Player);
app.use("/api/", Elf);
app.use("/api/", HighScore);
mongoose
.connect(mongoURI, {
useNewUrlParser: true,
useUnifiedTopology: true,
useUnifiedTopology: true,
})
.then(() => console.log("MongoDB connected..."))
.then(() => {
// log uri to console
console.log(`MongoDB connected to ${mongoURI}`);
})
.catch((err) => console.log(err));
app.listen(PORT, () => {
console.log(`Example app listening at ${PORT}`);
});
package.json
{
"name": "week1",
"version": "1.0.0",
"description": "",
"main": "server.js",
"scripts": {
"server": "nodemon server.js --ignore 'client/'",
"client": "npm run serve --prefix client",
"dev": "concurrently \"npm run server\" \"npm run client\"",
"start": "node server.js",
"build": "npm install --prefix client && npm run build --prefix client"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"body-parser": "^1.20.1",
"bootstrap": "^5.2.3",
"cors": "^2.8.5",
"dotenv": "^16.0.3",
"express": "^4.18.2",
"mongoose": "^6.7.5",
"morgan": "^1.10.0",
"portal-vue": "^2.1.7"
},
"devDependencies": {
"concurrently": "^7.6.0",
"nodemon": "^2.0.20"
}
}
Running within my dev environment at root dir using 'npm run dev', the app works flawlessly send/ receive data from mongoDB during this time. This starts up http://localhost:8080/. Also tried install of 'npm install -g serve' and running 'serve -s dist', this starts up serving at localhost:36797 and working flawlessly too.
I have tried to setup on Vercel & Render, both giving me the same issue where I'm not getting much feedback and the data isn't being fetched. Anyone else has this issue before?
I am trying to deploy my React app to heroku 22 stack, I have completed the code part of it and local machine it works fine. I have a Reactjs FrontEnd and Nodejs Backend. First After completing the project I moved my Reactjs frontend into the Nodejs Backend and run the npm run build command on the front end My folder structure looks like this:
but When I push my code to heroku using CLI
git push heroku master:main
I keep getting cannot get / or no such file or directory /app/vrestaurant/build/index.html
here is my package.json in backend
{
"name": "nodejs-mongodb-mongoose",
"version": "1.0.0",
"engines": {
"node": "17.x",
"npm": "8.x"
},
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "node app.js"
},
"author": "Vishal",
"license": "ISC",
"dependencies": {
"body-parser": "^1.19.1",
"connect-mongo": "^4.6.0",
"connect-mongodb-session": "^3.1.1",
"cors": "^2.8.5",
"crypto": "^1.0.1",
"debug": "^4.3.4",
"dotenv": "^16.0.1",
"express": "^4.17.2",
"express-session": "^1.17.2",
"mini-css-extract-plugin": "^2.4.6",
"mongoose": "^6.1.7",
"nodemon": "^2.0.19",
"passport": "^0.5.2",
"passport-local": "^1.0.0",
"passport-local-mongoose": "^7.0.0",
"razorpay": "^2.8.1",
"shortid": "^2.2.16"
}
}
my app.js file on backend
// imports
require('dotenv').config();
const express = require('express')
const session = require("express-session")
const bodyParser = require('body-parser')
const cors = require('cors')
const zomatoRoutes = require('./Routes/zomato')
const paymentRoutes = require('./Routes/payments')
const mongoose = require('mongoose')
const passport = require("passport")
const LocalStrategy = require("passport-local")
const passportLocalMongoose = require("passport-local-mongoose")
const MongoStore = require('connect-mongo');
const MongoClient = require("mongodb").MongoClient;
const User = require('./Models/user')
// create express server
var app = express()
// add middleware before routes
app.use(bodyParser.json())
app.use(cors())
//connect to mongoDB
const uri = 'mongodb+srv://vishal_torne_22:*****#db-hernode.zu6btrs.mongodb.net/<mydbname>?retryWrites=true&w=majority';
console.log(uri, "this is the uri")
const options = {
useNewUrlParser: true,
useUnifiedTopology: true,
dbName:'zomato1'
}
mongoose.connect(uri, options).then(() => {
console.log('mongoose connected')
}).catch(e => console.log(e))
mongoose.connection.on('connected', () => {
console.log('mongoose is connected')
})
app.use(session({
secret: "this is unambigous secret",
resave: false,
saveUninitialized: false,
cookie: { maxAge: 24*60*60*1000 },
store : MongoStore.create({
mongoUrl: uri,
ttl: 14 * 24 * 60 * 60
})
}));
app.use(passport.initialize());
app.use(passport.session());
// middleware routes
app.use('/zomato', zomatoRoutes)
app.use('/payment', paymentRoutes)
// heroku configuration
if(process.env.NODE_ENV=="production"){
app.use(express.static('vrestaurant/build'))
const path = require('path')
app.get("*", (req, res) => {
res.sendFile(path.resolve(__dirname, "vrestaurant/build/index.html"))
})
}
//listen to a port
app.listen( process.env.PORT ||5252 , () => {
console.log("express app is up and running on port 5252");
console.log(process.env.PORT,'this is the env port')
})
things I have tried :
I have added heroku post build but gives error ' Missing Build script'
I added build webpack in package.json but it gives me error
also added the https://github.com/mars/create-react-app-buildpack.git build pack using heroku website settings, It gives me error :
Downloading Buildpack: https://github.com/mars/create-react-app-inner-buildpack.git#v9.0.0
remote: =====> Detected Framework: React.js (create-react-app)
remote: Writing `static.json` to support create-react-app
remote: Enabling runtime environment variables
remote: =====> Downloading Buildpack: https://github.com/heroku/heroku-buildpack-static.git#21c1f5175186b70cf247384fd0bf922504b419be
remote: =====> Detected Framework: Static HTML
remote: Stack heroku-22 is not supported!
remote: ! Push rejected, failed to compile React.js (create-react-app) multi app.
can anybody help me out with this please? Thank you.
Your buildpack should be Node.Js and not react.
Also try to print the output of
path.resolve(__dirname, "vrestaurant/build/index.html") to verify if it is resolving to correct path for index.html file in build folder.
Provide full path in setting the static folder
app.use(express.static(path.resolve(__dirname, "vrestaurant/build/index.html")))
Actually it might be better for you to use os.path.join() because it can cause on error on different systems:
you can use:
const path = require('path');
app.get('*', (req, res) => {
res.sendFile(path.resolve(__dirname, 'vrestaurant', 'build', 'index.html'));
});
I am trying to deploy my first React.js app on Heroku. Everything seems to work fine link to app except the most important part - the Express.js REST API that I use to fetch data from my Postgres database and Stripe API is functioning normally on localhost, but when I deploy the app on Heroku, all the API routes I am trying to access return the same syntax error - Unexpected token < in JSON at position 0.
I understand that the issue is tied to how my app routes to the API. In other words, the fetch request is not able to get to the needed endpoint and thus return this syntax error, but I can't pinpoint exactly where is the issue - am I missing a '/' somewhere, have I incorrectly set up my environment variables, etc.?
Has someone had a similar issue or maybe someone can spot the issue in my code down below?
package.json
{
...
"private": true,
"main": "server.js",
"homepage": "https://dj-bbq.herokuapp.com",
"engines": {
"npm": "6.14.15",
"node": "14.18.1"
},
"dependencies": {
"#formspree/react": "^2.2.4",
"#stripe/react-stripe-js": "^1.7.0",
"#stripe/stripe-js": "^1.22.0",
"#testing-library/jest-dom": "^5.16.1",
"#testing-library/react": "^12.1.2",
"#testing-library/user-event": "^13.5.0",
"#userfront/react": "^0.2.22",
"cors": "^2.8.5",
"express": "^4.17.2",
"express-fileupload": "^1.2.1",
"helmet": "^5.0.1",
"jsonwebtoken": "^8.5.1",
"pg": "^8.7.1",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-router-dom": "^6.2.1",
"react-scripts": "4.0.3",
"stripe": "^8.195.0",
"web-vitals": "^2.1.2"
},
"devDependencies": {
"dotenv": "^10.0.0",
"nodemon": "^2.0.15",
"source-map-explorer": "^2.5.2"
},
"scripts": {
"start": "node server.js",
"heroku-postbuild": "npm install && npm run build",
"dev-start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject",
"analyze": "source-map-explorer 'build/static/js/*.js'",
"server": "node server.js",
"nodemon": "nodemon server.js"
},...
server.js
const express = require('express');
const helmet = require('helmet');
const cors = require('cors');
const path = require('path'); // Allows to access files through the server in our filesystem
const fileUpload = require('express-fileupload'); // Parses multipart/form-data requests, extracts the files if available, and make them available under req.files property.
/**
** ------------- GENERAL SETUP -------------
*/
// Provides access to variables from the .env file by using process.env.REACT_APP_variable_name
require('dotenv').config();
const nodeEnv = process.env.NODE_ENV !== 'production';
const devPort = process.env.REACT_APP_server_dev_port;
const prodPort = process.env.PORT // process.env.PORT
const devDomain = process.env.REACT_APP_dev_domain;
const prodDomain= process.env.REACT_APP_prod_domain;
const PORT = nodeEnv ? devPort : prodPort;
const domain = nodeEnv ? devDomain : prodDomain;
// CORS options
const corsOptions = {
origin: domain, // frontend_URL for heroku deployment
credentials: true ,
// Allows only the following HTTP requests to go through
methods: [
"PUT",
"POST",
"DELETE",
"GET",
],
"Access-Control-Allow-Headers": [
"Origin",
"X-Requested-With",
"Content-Type",
"Accept",
"Authorization",
],
};
//* Creates the Express server instance as "app"
const app = express();
//* MIDDLEWARE
// Called BETWEEN processing the Request and sending the Response in your application method.
app.use(helmet()); // Sets many http headers to make them more secure
app.use(cors(corsOptions)); // To allow cross origin conections (Allows our React app to make HTTP requests to Express application)
// Instead of using body-parser middleware, use the new Express implementation of the same thing
app.use(express.json()); // To recognize the incoming Request Object (req.body) as a JSON Object
app.use(express.urlencoded({ extended: true })); // To recognize the incoming Request Object as strings or arrays
app.use(fileUpload({
createParentPath: true
})); // Enables file uploading
//* HEROKU MIDDLEWARE
if (process.env.NODE_ENV !== 'production') {
// To load static files or client files from here http://localhost:3000/images/kitten.jpg
app.use(express.static(path.join(__dirname, 'public')));
} else if (process.env.NODE_ENV === 'production') {
// Serve static files - makes the build folder accessible to app.
app.use(express.static(path.joins(__dirname, 'build')));
// app.use(express.static(path.resolve(__dirname, 'build')));
}
/**
** -------------- SERVER ----------------
*/
// Determines the PORT and enables LISTENing for requests on the PORT (http://localhost:8000)
app.listen(PORT, () => {
console.debug(`Server is listening at http://localhost:${PORT}`);
});
/**
** ------- ROUTES / ENDPOINTS ---------
*/
// Go to /test to make sure the basic API functioning is working properly
app.get('/test', (req, res) => {
res.status(200).send('The Basic API endpoints are working.')
});
// Imports all of the routes from ./routes/index.js
app.use(require('./app-server/routes/allRoutes'));
// If req comes from one of these domains (origins), then allow the request with CORS.
app.use((req, res, next) => {
const corsWhitelist = [
domain,
];
if (corsWhitelist.indexOf(req.headers.origin) !== -1) {
res.header('Access-Control-Allow-Origin', req.headers.origin);
}
next();
});
I have set-up a catch all route (router) for unkown routes in a different file
//* HEROKU - catch all for unrecognised routes
if (process.env.NODE_ENV === 'production') {
// Serve index.html file if it doesn't recognize the route
router.get('*', (req, res, next) => { // or * instead of /
res.sendFile(path.join(__dirname, 'build', 'index.html')); // resolve instead of join
})
}
And here is an example of a fetch request
const [recipes, setRecipes] = useState([]);
useEffect(() => {
let interval;
const fetchData = async () => {
try {
// const url = 'http://localhost:8000/recipes/display';
const url = `${customProxy}/recipes/display`;
const response = await fetch(url);
const json = await response.json();
setRecipes(json);
} catch(error) {
// console.error(error);
alert("Recipe displaying:" + error);
}
};
fetchData();
interval = setInterval(() => {
fetchData()
}, 86 * 1000)
return () => {
clearInterval(interval)
}
}, []); // Determine swhen to re-use useEffect, if this changes.
Thank you in advance for taking the time to consider the solution for issue!
Update 1
I started going through my project for the n-th time and previously I followed the guides found on Heroku to deploy my PERN app. The guides recommended using mars/create-react-app-buildpack to deploy the app, but after reading the documentation of this build pack it clearly says that this build pack is only meant for static react apps not react apps with its own custom node.js server.
In such cases, I am to use the mars/heroku-cra-node.
I have been following the documentation on how to set-up my folder structure, etc., but now, when I deploy the app, Heroku informs me of the following...
-----> Building on the Heroku-20 stack
-----> Using buildpacks:
1. https://github.com/mars/heroku-cra-node
-----> App not compatible with buildpack: https://github.com/mars/heroku-cra-node
bash: /tmp/codon/tmp/buildpacks/d07ae047a3685d9cfb39224105301a7dbdbfbe9c/bin/detect: No such file or directory
More info: https://devcenter.heroku.com/articles/buildpacks#detection-failure
! Push failed
I understand that the idea is that my folder structure is not as required by the build pack, but I am following its documentation by the letter.
Has anyone had any experience in using this build pack to deploy a PERN app to Heroku?
I noticed that this question of mine is still unanswered.
The issue, in the end, was that I was trying to use the Heroku free plan, but my app was too "big" for that so I either needed to split the back-end and front-end into two apps or to use a paid plan.
In the end, I actually changed my hosting service provider from Heroku to Digital Ocean. The app is still on their servers and works now - https://dj-bbq-i5gdc.ondigitalocean.app/ .
Hi Guys, I have created a little project of Mern stack. I am deploying it correctly on Heroku. But as soon as I am checking her on Heroku after deploying, then Failed to load resource: the server responded with a status of 503 (Service Unavailable) error is coming.
But as soon as I run heroku local in cmd after deploying then it is working correctly. I am giving below the heroku setup code. Please guide me. please ........
package.sjon file of backend
{
"name": "app",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "npm install && node index",
"heroku-postbuild": "NPM_CONFIG_PRODUCTION=false npm install --prefix client && npm run build --prefix client"
},
"dependencies": {
"config": "^3.3.1",
"express": "~4.16.1",
"express-fileupload": "^1.1.7-alpha.3",
"mongoose": "^5.9.12",
"nodemailer": "^6.4.6"
},
"keywords": [],
"author": "",
"license": "ISC"
}
Index.js file of backend
var express = require('express');
var path = require('path');
const connectDB = require('./config/db')
var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');
var studentRouter = require('./routes/student')
var app = express();
connectDB();
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(express.static(path.join(__dirname, 'public')));
app.use(express.static('client/build'))
app.get('/', (req, res) => {
res.sendFile(path.resolve(__dirname, 'client', 'build', 'index.html'))
})
app.use('/', indexRouter);
app.use('/', studentRouter);
app.use('/users', usersRouter);
if (process.env.NODE_ENV == "production") {
app.use(express.static('client/build'))
app.get('*', (req, res) => {
res.sendFile(path.resolve(__dirname, 'client', 'build', 'index.html'))
})
}
var port = process.env.PORT || '8000';
app.listen(port, () => {
console.log(`server run port ${port}`);
})
module.exports = app;
All these codes are absolutely correct. I had a problem creating a cluster in mongodb atlas. The problem was that I had selected add current ip address while creating the cluster. Whereas I had to select allow from anywhere. So now I have selected the book. And now it is doing the right thing.
In my case, changing network access form anywhere in my MongoDB cluster, fixed the problem.
Also, don't forget to hit restart all dynos.
For my express app I want to use Parse to handle all my data. As Parse's hosting options for web apps seem very limited (caped at 500 files and 500MB), I want to use Heroku to host my app. I have managed to set up my express app on Heroku, but can not quite figure out how to get access to my Parse app in it. I've searched around, but there does not seem to be too much documentation on this, and I am struggling to get it to work.
Here is my index.js for my express app:
var express = require('express');
var bodyParser = require('body-parser')
var app = express();
app.set('port', (process.env.PORT || 5000));
app.use(express.static(__dirname + '/public'));
// views is directory for all template files
app.set('views', __dirname + '/views');
app.set('view engine', 'ejs');
app.use(bodyParser.urlencoded({
extended: true
}));
app.use(bodyParser.json());
app.get('/', function(request, response) {
response.render('pages/public');
});
app.get('/login', function(request, response) {
response.render('pages/login');
});
// Clicking submit on the login form triggers this.
app.post('/login', function(req, res) {
Parse.User.logIn(req.body.username, req.body.password).then(function() {
// Login succeeded, redirect to homepage.
res.redirect('pages/loggedin');
},
function(error) {
// Login failed, redirect back to login form.
res.redirect('pages/login');
});
});
In app.post('/login'I have the Parse function I would use to log in users, but as Parse is not connected it just throws an error. How do I let my Express app get data from Parse?
My package.json files looks like so:
{
"name": "node-js-getting-started",
"version": "0.1.4",
"description": "A simple Node.js app using Express 4",
"main": "index.js",
"scripts": {
"start": "node index.js"
},
"dependencies": {
"ejs": "^2.3.1",
"express": "~4.9.x",
"body-parser": "1.13.x"
},
"engines": {
"node": "0.12.2"
},
"repository": {
"type": "git",
"url": "https://github.com/heroku/node-js-getting-started"
},
"keywords": [
"node",
"heroku",
"express"
],
"license": "MIT"
}
Thanks for any help!
Another hour of googling and I came across these links which proved useful:
https://medium.com/#spacekid/getting-started-with-parse-node-js-express-b2c79798cc7d
http://blog.parse.com/learn/engineering/the-javascript-sdk-in-node-js/
Before using Parse.User.logIn() and so on (or any other node.js module), you must make sure you actually include it like you include bodyParser module.
For example:
var Parse = require('node-parse-api').Parse;
Have a look at this module: Node Parse API