Vercel build never ends - node.js

I'm having a problem with Vercel platform, probably because I'm not using it right.
Locally I can deploy the server without problems on port 3000.
But when I want to deploy in Vercel, Build gets stuck at the express function app.listen().
Image Vercel error:
My index.js is like any other and ends with the function:
// listening the server
app.listen(app.get('port'), () => {
console.log('Server on port ', app.get('port'));
});
I've tried everything I don't know what to do anymore, surely I have a conceptual error.

Vercel is for front-end (and serverless)
Sites deployed on Vercel are mainly front-end. (React, Vue, and everything else that becomes HTML/CSS/JS).
By the looks of it you're trying to run a back-end application (Node.js) on Vercel, which it isn't designed for. (Instead, consider using a VPS or a managed environment/app platform)
Vercel also supports serverless functions, which you could use to run your back-end with. These are essentially one-off functions that are run on a new server instance every time a request comes in.
All that considered, if you're indeed trying to build and deploy a front-end app...
A wild guess
Your build script is calling your node application. You might have something like the following in your package.json:
"scripts": {
"build": "tsc && node src"
}
This would run tsc first, then start the application by running the built files.
However, you don't want to start your application as part of the build process -- instead, make the build command only build your app, nothing more.
Then, on Vercel, go to your project's settings page and make sure that command is used to Build your app.
My app doesn't need to be built (I've already got plain HTML/CSS/JS files)
If your app doesn't need to be built at all, go to your project's settings page and remove the "Build Command" entirely.

Related

Accessing user uploaded images in a deployed MERN app

I am a relatively new developer and I have made a personal blog app, where a user can create a post and upload an image to use as the thumbnail for that post.
So far the backend and frontend work brilliantly and I am able to get the image, store it locally in a folder on my machine, store the file path in MongoDB and then access it and display it in the UI accordingly.
Now that I'm looking to finally deploy my application I have to figure out a way to upload images to an online cloud storage or something, where I can access them from my frontend as well.
Any suggestions on a good service of this kind and if possible, something free, suitable for my small project? Or any suggestions on an alternative way of dealing with this situation?
Any advice will be greatly appreciated!
Thanks in advance!
NOTE: I plan on deploying my app with Heroku, so if you've ever dealt with this issue directly using Heroku, please share your experience.
Yes, I have several apps that do just this! Sign up for a free MongoDB Atlas account and then you can store the data on their servers and point your Express app to the connection URL. Basically, they will give you a URL like this:
mongodb+srv://your-cluster-name:a232dfjoi39034r#atlas-free-cluster-czaoo.mongodb.net/blog-app?retryWrites=true
Which you can then store in a .env file like this:
MONGODB_URL=mongodb+srv://your-cluster-name:a232dfjoi39034r#atlas-free-cluster-czaoo.mongodb.net/blog-app?retryWrites=true
And access from your app like so:
mongoose.connect(process.env.MONGODB_URL, connectionOptions)
.catch((err) => {
console.log('Error on initial DB connection: ', err);
});
You'll need to load the .env files in your app using an npm packages such as dotenv on the development side. For heroku, you can use the heroku-cli
and set any environment variables for your app like so:
heroku config:set MONGODB_URL=mongodb+srv://your-cluster-name:a232dfjoi39034r#atlas-free-cluster-czaoo.mongodb.net/blog-app?retryWrites=true
Note, the development MongoDB URL could be a connection string to a local instance, such as:
MONGODB_URL=mongodb://localhost:27017/my-blog-app
And the one for heroku can be the MongoDB Atlas cluster.
There are a few other config things to do for Node apps, like having a 'start' script in package.json, which for Express apps created with express-generator looks like:
"scripts": {
"start": "node ./bin/www"
But for your case may be different. It should point to whatever file is the entry point for your server.
You'll also need to set the PORT from process.env.PORT, which heroku will set on their end, and on your end you can just default to 3000:
const PORT = process.env.PORT || 3000;
app.listen(PORT);
If you have any questions, feel free to PM me or just ask here and I can elaborate further. It can be intimidating the first few times, but it's actually really easy to deploy stuff to heroku this way once you get the hang of it! You can also check out the heroku docs for deploying Node apps.

fs.existsSync is not a function error when requiring grpc through create-react-app

We are trying to get gRPC to work with React (actually we were trying to get it to work with React-Native but gave up on that for now).
Using plain node.js things are pretty straight forward if you follow this example.
We started by using create-react-app but when we started the app, we got the following error:
existsSync is not a function
That was casued by this bit in pre-binding.js belonging to the node-pre-gyp package located in grpc:
var existsSync = require('fs').existsSync || require('path').existsSync;
My understanding is that something goes on with Webpack (or some other process run by create-react-app) that goes and returns and empty object instead of require('fs').
Any ideas of how to get this to work without having to give up on the wonders of create-react-app?
To test it out you can just follow these 2 easy steps:
create-react-app test-app
add import grpc from 'grpc'; in the App.js file
Basically, from what I understand now, you are not really supposed to use gRPC + Protobuf directly from any frontend but rather it is more common to use the grpc node package on node.js server-side code and then communicate with the browser-side code using Express.
The server-side code on node.js then communicates using grpc with the microservices.
We are testing out the use of Firebase Functions to communicate securely with the frontend and Firebase Functions communicate with the Go microservices using grpc.

node.js error ECONNREFUSED on localhost url only

I have a node app, hosted on heroku, where I'm trying to hit an API that returns some JSON. That API I'm calling lives with the same app that I'm calling it from (e.g. The node app hosts my web app and has an API that generates JSON from my db).
I'm using the request npm module to make my API call. When deployed to heroku, when I use localhost:8080 as the url in the function I get the error below, but when I use the actual url where my app is hosted on heroku, it works fine. I have dev/staging/prod environments so I don't want to hard code the url.
Thing is, it works fine locally on my machine, so I'm not sure what the issue is - I'm assuming it has something to do with heroku since that's the only difference, but I'm not very familiar with this type of error.
Also - if it helps, I can hit both urls in the browser fine, locally, and on the heroku app.
request('http://localhost:8080/api/pictures', function (error, response, body) {
// this throws error: "connect ECONNREFUSED"
});
request('http://myapp.herokuapp.com/api/pictures', function (error, response, body) {
// this works
});
connect ECONNREFUSED: the two things you want to look at first:
Is the service you're trying to connect to enabled and started?
Is there are firewall between the client and the service host/service port?
In your case:
1) I assume you've started Heroku locally (on a Windows PC?)
2) I also assume it's running on port 8080 (per your notes)
3) Please check your local firewall software, to make sure Heroku and/or port 8080 are enabled. Do you have any antivirus programs (which might introduce their own firewalls)?
4) Also, please look at these links:
http://windows.microsoft.com/en-us/windows/communicate-through-windows-firewall#1TC=windows-7
http://windows.microsoft.com/en-us/windows/open-port-windows-firewall#1TC=windows-7
https://github.com/heroku/heroku/issues/1046
http://www.debian-administration.org/article/120/Application_level_firewalling

Use test database with grunt and mocha

I am building a web app in Node.js, Express, and MongoDB using Mongoose. I want to have a dedicated database for when i run my Mocha tests with Grunt so that I do not mess up the database I am using for development. How would I do this?
I currently have my development database configuration information in a file at /config/db.js, which is loaded and connecting to my development database in my app.js file at startup. How would I make my Mocha tests, that are run in a Grunt task, use a test database dynamically when I run Grunt? I have tried to disconnect from development database in my test files in the before() hook in my Mocha test files, and then connect to test database. However, it keeps using development database. An example is the following:
before(function(done) {
if(mongoose.connection.db) mongoose.connection.close();
mongoose.connect(<test_db_uri>, done);
}
Your question is near of the following question Test environment in Node.js / Express application.
Basicly what you should do is use an env variable ('NODE_ENV' for exemple) access it with process.env.NODE_ENV and base on its value call the right configuration file. You should take a look to grunt-express-server which helps you a lot with the environement setup.
I hop this will help!

How to get grunt.js to start an express app for testing

My current situation is that I use grunt to make a production version of my express app (minimize and merge all the js/css, copy all the files in place) and then I have to run a script which sets an environment variables (my app only serves the test harness when running in TEST mode), creates an empty Mongo test database and then calls npm start on the application directory, and then I manually have to run the tests from either Chrome or Phantom, what I want to do is have grunt set the environment variable and run the server, run the tests, and then stop the server (in the future if all is successful it would be nice to have it deploy as well). However when I try to run the app in grunt, it gets stopped as soon as it is completed.
How do I have grunt start the app, wait until it is started and then run tests?
If you check grunt-express which is a plugin for express web-server tasks via grunt.
express-keepalive
Note that this server only runs as long as grunt is running. Once
grunt's tasks have completed, the web server stops. This behavior can
be changed by appending a express-keepalive task at the end of your
task list like so
grunt.registerTask('myServer', ['express', 'express-keepalive']);
Now when you run grunt myServer, your express server will be kept alive
until you manually terminate it.
Such feature can also be enabled ad-hoc by running the task like grunt express express-keepalive.
This design gives you the flexibility to use grunt-express in
conjunction with another task that is run immediately afterwards, like
the grunt-contrib-qunit plugin qunit task. If we force express task to
be always async, such use case can no longer happen.
From the guide grunt-contrib-qunit package is used to run QUnit unit tests in a headless PhantomJS instance. Also mind the last line, if you force express to be always async it would be of no use.
npm link for grunt-express.
I'm not sure if I understand your problem correctly, but probably this helps:
Do you know about Grunt's async function? For some time I used the following approach to start (and stop) my Express app. I used it with watch, so it automatically restarted on save. In this case you have to set watch's nospawn option to true.
var server = null;
grunt.registerTask('server', 'Start server', function() {
var done = this.async();
if (server !== null) {
server.close();
clearCache();
}
var app = require('./my-express-app.js');
server = http.createServer(app).listen(app.get('port'), function(){
done();
});
});
function clearCache() {
for (key in require.cache) {
if (key.indexOf(__dirname + '/node_modules/') == -1) {
delete require.cache[key];
}
}
}
It is ugly because of this require-cache-hack. However, it works.

Resources