How do I deploy a static React "app" to Heroku? - node.js

Title was: How do I fix "Cannot use import statement outside a module" error on Heroku without causing a "Must use import to load ES Module" error?
This was before I understood that I was trying to deploy a "static" React "app" and Heroku was running index.js as if it was server code.
I had setup Procfile to contain:
web: node ./src/index.js
Then I saw this error:
...
2020-03-29T02:34:01.000000+00:00 app[api]: Build succeeded
2020-03-29T02:34:02.637867+00:00 heroku[web.1]: State changed from starting to crashed
2020-03-29T02:34:02.622526+00:00 heroku[web.1]: Process exited with status 1
2020-03-29T02:34:02.583667+00:00 app[web.1]: /app/src/index.js:1
2020-03-29T02:34:02.583689+00:00 app[web.1]: import React from 'react';
2020-03-29T02:34:02.583690+00:00 app[web.1]: ^^^^^^
2020-03-29T02:34:02.583690+00:00 app[web.1]:
2020-03-29T02:34:02.583691+00:00 app[web.1]: SyntaxError: Cannot use import statement outside a module
2020-03-29T02:34:02.583691+00:00 app[web.1]: at wrapSafe (internal/modules/cjs/loader.js:1072:16)
...
I tried to fix it by adding this to package.json:
"type": "module",
And then I got this error:
...
2020-03-29T03:05:01.000000+00:00 app[api]: Build succeeded
2020-03-29T03:05:06.293573+00:00 heroku[web.1]: Starting process with command `node ./src/index.js`
2020-03-29T03:05:08.744086+00:00 heroku[web.1]: State changed from starting to crashed
2020-03-29T03:05:08.724957+00:00 heroku[web.1]: Process exited with status 1
2020-03-29T03:05:08.650103+00:00 app[web.1]: internal/modules/cjs/loader.js:1174
2020-03-29T03:05:08.650125+00:00 app[web.1]: throw new ERR_REQUIRE_ESM(filename, parentPath, packageJsonPath);
2020-03-29T03:05:08.650126+00:00 app[web.1]: ^
2020-03-29T03:05:08.650126+00:00 app[web.1]:
2020-03-29T03:05:08.650126+00:00 app[web.1]: Error [ERR_REQUIRE_ESM]: Must use import to load ES Module: /app/src/index.js
2020-03-29T03:05:08.650127+00:00 app[web.1]: at Object.Module._extensions..js (internal/modules/cjs/loader.js:1174:13)
2020-03-29T03:05:08.650127+00:00 app[web.1]: at Module.load (internal/modules/cjs/loader.js:1002:32)
...
I should've noted that my React "app" is a front-end only that uses a GraphQL API I've already deployed elsewhere. In other words, there is no "server.js that serves [my] react app". (HMR's comment led me to that realization. I guess the correct terminology would be to call this a "static app".)
This code in server.js only slightly adapted from Tin Nguyen's answer works:
const http = require('http');
const path = require('path');
const express = require('express');
let wss;
let server;
const app = express();
app.use(express.static(path.join(__dirname, './build')));
server = new http.createServer(app);
server.on('error', err => console.log('Server error:', err));
server.listen(process.env.PORT);
...with this Procfile:
web: node ./server.js
The only change is the path to the build directory, which I tweaked after snooping around with heroku run bash.
My site isn't working properly, but I think that is the result of my build not being correct. Perhaps that can be solved with a buildpack. But that belongs in a different question. (And I might not bother figuring it out since I plan to take Tin Nguyen's advice and try hosting on GitHub.)
Update: The problem wasn't with my build, but with client-side routing (as described on https://create-react-app.dev/docs/deployment/). This code (from that page) fixes it (in server.js):
const express = require('express');
const path = require('path');
const app = express();
app.use(express.static(path.join(__dirname, 'build')));
app.get('/*', function (req, res) {
res.sendFile(path.join(__dirname, 'build', 'index.html'));
});
app.listen(process.env.PORT);
The link in HMR's comment helped me reach this understanding, but Dave Ceddia writes that his article covers how to keep a React app and API server together. Is there any documentation on how to deploy a front-end on Heroku (or elsewhere) with an API server already deployed elsewhere?
(I found this answer where Paras recommends Netlify.)

If I am reading it right you have a static website and you want it to be hosted on Heroku.
Static websites can be served on Netlify and also GitHub pages. They don't require a web server. You can still host it on Heroku by wrapping a web server around it that is then serving your static files.
const http = require('http');
const path = require('path');
const express = require('express');
let wss;
let server;
const app = express();
app.use(express.static(path.join(__dirname, './../build')));
server = new http.createServer(app);
server.on('error', err => console.log('Server error:', err));
server.listen(process.env.PORT);
How do you know if you have a static website?
You should have generated build files somewhere in your project. You can navigate to the folder and open index.html. The website should work even though you don't have node or npm running. That folder is in my example ./../build.
Personally I would recommend you host static websites on GitHub over Heroku. Heroku is "free" but with a lot of limitations. The dyno hours are limited, websites need to spin up after not being in use for a long time, etc.

try changing your command:
node ./src/index.js
to:
node --experimental-modules ./src/index.js
Try for both with and without fix of package.json with
"type": "module"

Actually, this comes from using ES6 import inside the NodeJS environment. there is two way, using require instead of import in the server-side JavaScript files:
import something from 'something';
↓↓↓
const something = require('something');
Or use babel node on the server environment to run the project:
node ./src/index.js
↓↓↓
babel-node [options] [ -e script | ./src/index.js ] [arguments]
A complete example could be like below:
npx babel-node --presets es2015 -- ./src/index.js
By reading your errors, I guess the second way is better for your case. but at first please remove your solution, I mean the "type": "module",.

Related

Nodemon restarts, but saved changes to index.js not reflected in output

Here's my code for an express server:
const express=require('express');
express();
const app=express();
app.get('/',(req,res)=>{
res.send('Welcome to API xyz!');
});
app.listen(3000,()=>{
console.log('Listening on port 3000...');
});
Running the server from a git bash terminal, in the app's directory, using:
nodemon index.js
initially gives the message:
[nodemon] starting `node index.js`
Listening on port 3000...
Whenever I save a change to the output of res.send() as follows:
res.send('Welcome to API abc!');
and save the index.js file, I get this message:
[nodemon] restarting due to changes...
but I do not get the console.log() text, and when I reload localhost:3000 in Chrome, I still get the output:
Welcome to API xyz!
How can I get the server to update in response to saved changes without having to stop nodemon and restart it (which is the whole point of running nodemon in the first place)?
EDIT: I noticed that when nodemon restarts, I get:
restarting due to changes...
but I don't get
starting `node index.js`
after that. I only get
starting `node index.js`
when I first run nodemon.
EDIT 2: thinking that maybe this is related to the same issue that other nodemon users have experienced, as noted here in its Github issues log?
Maybe try removing the 2nd line that says express();
const express = require("express");
const app = express();
app.get("/", (req, res) => {
res.send("Welcome to API xyz!");
});
app.listen(3000, () => {
console.log("Listening on port 3000...");
});
I was facing the same issue and I usually start the server from VS code terminal. Before I could try the solutions given in a related question I tried running the server from the command prompt (Run as administrator) and it worked.
I use the command npm run start to start the server.
Hope it helps someone!

PM2 couldn't start the app and the app ends up in "errored" status

I am using Node/Express.js server on Windows Server 2012 R2 in the production and PM2.js to keep applications alive forever and to reload them without downtime. Since PM2 has limitations on Windows OS, I have chosen PM2-installer software to overcome them.
The server runs fine when I run with Node, so there is no issue with the server script.
node index.js
But, when I start the server with PM2, the server doesn't start and the status is "errored" (I had tried ecosystem file and cluster mode as well earlier with no luck).
pm2 start index.js
The logfile is empty, so there is no clue. Has anybody encountered this? Any solution?
Update 1:
I noticed the following error in service.log in C:\ProgramData\pm2\service
2021-03-23T23:13:56: PM2 log: App [server-plugin:0] starting in -fork mode-
2021-03-23T23:13:56: PM2 log: App [server-plugin:0] online
ERROR: 2021-03-23T23:13:56: PM2 error: Error: spawn node ENOENT
at Process.ChildProcess._handle.onexit (internal/child_process.js:269:19)
at onErrorNT (internal/child_process.js:465:16)
at processTicksAndRejections (internal/process/task_queues.js:80:21)
3/23/2021, 11:13:56 PM: default/server-plugin#N/A - start - MANUAL
ERROR: 2021-03-23T23:13:56: PM2 error: Cancelling versioning data parsing
The error seems to indicate that it is not able to spawn node.js, but not sure why.
Update 2:
index.js is small test App directly in root folder and contains just this:
const fs = require('fs');
const express = require('express'),
https = require('https'),
const config = require('./config');
const hostname = config.hostname;
const port = config.port;
const app = express();
app.get("/*",(req, res, next) => {
console.log(req.headers);
res.send(`<html><body><h1>Hello ${req.params[0] || 'World'} from ${port} port!</h1></body></html>`);
});
https.createServer({
key: fs.readFileSync('server.key'),
cert: fs.readFileSync('server.cert')
}, app).listen(port, hostname, () => {
console.log(`Server running at https://${hostname}:${port}`);
There is an accompanying config.js, the SSL files and node_modules sub-folder in the root folder. That's all.
The solution for me was to abandon pm2-installer and use a Task scheduler approach. This solution was the savior. It works like a charm. An additional tip is to set the environment variable PM2_HOME to c:\users\<user>\.pm2 or something like that. This will help PM2 resurrect to pick up the dump file from this location. Also restart the machine for this scheme to work but if it is not possible to restart, run the created scheduled task manually.

Stop Past Express JS or React Builds from Running

I have been developing an app from the create-react-app starting project.
Today I have been doing the following on my local machine:
deploying my react app using react-scripts start
deploying my react app by using react-scripts build then either serving the build by either...
(A) using the [npm module serve][] as follows serve -p 4001
(B) or attempting to server using a express app like follows:
Express app:
const express = require('express');
const path = require('path');
const app = express();
app.use(express.static(path.join(__dirname, 'build')));
app.get('/', function (req, res) {
res.sendFile(path.join(__dirname, 'build', 'index.html'));
});
app.listen(4001);
I've just restarted my computer and it's still serving the site at:
http://localhost:4001/ and I cannot figure out how to stop it.
I wouldn't mind the continuous deployment of this server but when I build the project again. The changes are not reflected.
The only work around I've come up with is to now deploy at port 4025 and use the Express method coded above.
How the hell can I get rid of this weird residual app that continues to run (via some react process) at port 4001?
I'd really like that port back for sake of keeping it the same across different machines :(
Turns out that chrome keeps react apps running even if the server stops providing them.
Go to chrome://serviceworker-internals and unregister them.

My socket.io app's server is not starting on Heroku

I'm trying to deploy my app on Heroku. I've followed these instructions: https://devcenter.heroku.com/articles/getting-started-with-nodejs, enables websockets, but when I run $heroku open, the I land on the error page.
Here are the logs I get from heroku:
2014-07-14T11:41:27.331343+00:00 heroku[web.1]: Starting process with command `node index.js`
2014-07-14T11:41:28.431660+00:00 app[web.1]: info: socket.io started
2014-07-14T11:42:27.710153+00:00 heroku[web.1]: Error R10 (Boot timeout) -> Web process failed to bind to $PORT within 60 seconds of launch
2014-07-14T11:42:27.710206+00:00 heroku[web.1]: Stopping process with SIGKILL
2014-07-14T11:42:28.915226+00:00 heroku[web.1]: Process exited with status 137
2014-07-14T11:42:28.927884+00:00 heroku[web.1]: State changed from starting to crashed
Here is the index.js file of my app:
// Import the Express module
var express = require('express');
// Import the 'path' module (packaged with Node.js)
var path = require('path');
// Create a new instance of Express
var app = express();
// Import Anagrammatix game file.
var agx = require('./game');
// Create a simple Express application
app.configure(function() {
// Turn down the logging activity
app.use(express.logger('dev'));
// Serve static html, js, css, and image files from the 'public' directory
app.use(express.static(path.join(__dirname,'public')));
});
// Create a Node.js based http server on port 8080
var server = require('http').createServer(app).listen(8080);
// Create a Socket.IO server and attach it to the http server
var io = require('socket.io').listen(server);
// Reduce the logging output of Socket.IO
io.set('log level',1);
// Listen for Socket.IO Connections. Once connected, start the game logic.
io.sockets.on('connection', function (socket) {
//console.log('client connected');
agx.initGame(io, socket);
});
The node_modules I'm using are:
- express
- mysql
- socket.io
Do you know what I should change to get the app work? Let me know if you need me to provide more info.
Thanks!
Your code is trying to bind to a hard-coded port 8080, but Heroku will tell your app which port to connect to. Heroku uses this to detect that your app's started correctly, as well as for routing. Your code's not starting on that port, though, so it gets killed with the error "Web process failed to bind to $PORT within 60 seconds of launch". Heroku doesn't know that your app has started, and it doesn't know which port it's listening to.
It's an easy fix, though. This will tell your app to connect to the port specified in the PORT environment variable, or 8080 if that variable isn't set:
var server = require('http').createServer(app).listen(process.env.PORT || 8080);

Node.js app works locally but heroku says missing module

I made a simple chat application using Node.JS and Socket.IO, everything works fine locally, but when I push it to heroku it gives me an application error, when I check the logs, this is the error:
Error: Cannot find module 'indexof'
at Function.Module._resolveFilename <module.js:338:15>
at Function.Module._load <module.js:280:25>
at Module.require <module.js:364:17>
at require <module.js:380:17>
at Object.<anonymous> </app/node_modules/socket.io/node_modules/socket.io-parser/node_modules/emitter/index.js:6:13>
at Module._compile <module.js:456:26>
at Object.Module._extensions..js <module.js:474:10>
at Module.load <module.js:356:32>
at Functin.Module._load <module.js:312:12>
at Module.require <module.js:364:17>
So I figured out that indexof is a module that Socket.IO uses, and it is in my node_modules folder, but for some reason either it's not being pushed to heroku or it's just not being recognized. I reinstalled my modules 5-6 times and recreated the app but it's still giving me the same error. My package.json file has 3 dependencies: Express, Socket.IO and Jade
Alright so after 2 hours I figured the problem out, multiple folders named "emitter" that contained the indexof module also had a gitignore file that made git ignore the module, no idea why that was even there, but deleting them fixed the problem
In my case I had to add a few modules to dependencies, as they were only under devdependecies and were not built on production
I had the same problem , please read it carefully
These are solutions to socket.io related problems
I hope i will work
Ports in your (index.js or server.js) & (index.html and your client.js) port must be different. (refer below code)
=============your index.js file ======================
(port here is 8000)
const express = require("express")
var app = express();
const http = require('http')
var server = http.createServer(app);
const port = process.env.PORT || 8000
server.listen(port,()=>
{
console.log("Listening at port => "+port)
});
var io = require('socket.io')(server, {
cors: {
origin: '*',
}
});
const cors = require("cors")
app.use(cors())
=============your client.js file ======================
port here is 8080
const socket = io.connect('https://localhost:8080/')
=============your index.html file ======================
port here is 8080
<script defer src="https://localhost:8080/socket.io/socket.io.js">
</script>
Remember your "server.js or index.js" port should be different from "client.js" port (Rememeber this is important)
(index.html and your client.js) port must be same
You should always use 'http' while working with socket.io (refer above code)
U may not included cors as it allows u to have more resourses , without cors heroku prevent some dependencies to not install in heroku (refer above code)
Try replacing "io" to "io.connect"
const socket = io.connect('https://localhost:8080/')
Must write tag at the end in the HTML
U may forget to add this code which is must in "socket.io"
It is required in your html file
delete "node_modules" and "package-lock.json"
and write "npm i" in cmd
This should be in package.json 's scripts
"start":"node index.js",
I am not talking about nodemon , use simple node over here
May be version is creating a problem , u can avoid it by copying all "devDependencies" to "dependencies" in "package.json" and put "*" in version like this
"dependencies": {
"cors": "*",
"express": "*",
"nodemon": "*",
"socket.io": "*"
},
"devDependencies": {}

Resources