filesending for index.html overrides all get apis - javascript

I have MERN application, where I serve index.html on all routes. But bellow that, I declare another apis for request.
router.post('/add-bin', newBin);
router.get('/recent-bins', recentBins);
router.get('/fetch-bin/:filename', fetchBin);
app.use(router);
app.get('*', (req, res) => {
res.sendFile(path.join(__dirname, 'build', 'index.html')); // Front is built with react
});
In the development mode, where I was using proxy, everything was going fine, but when I deployed my web application on heroku, All the GET apis are overrode by that app.get("*" ...) part.
P.S I am quite new to Node and Express.

First, in client run npm run build this will generate the build folder, where will be your frontend production code. In your backend you should serve that folder (this usually will be done in your index.js).
app.use(express.static('path/to/client/build'))
app.get('*', (req, res) => {
res.sendFile(path.join(__dirname, 'build', 'index.html')); // Front is built with react
});
After that, you'll need to add some commands (in your package.json) to prepare the client for the deploy.
"scripts": {
"build": "cd path/to/client && npm run build",
//we'll need to install client packages
"i-client-packages": "cd client && npm install",
//heroku will execute this command post-build
//this will be needed to run the previous commands
"heroku-postbuild": "npm run i-client-packages && npm run build"
//...the other commands (start, test, etc...)
}
More info about how to deploy a MERN app to heroku here.

Related

How do I run an API endpoint deployed to Vercel? (not using Next.js)

I've got a bit of a weird set up here with a codebase that I inherited. It's a CRA app deployed to Vercel but doesn't use Next.js.
Problem: I'm not able to call myapp.com/nonce from Postman or access it in my browser to see the JSON response. There's some configuration stuff that's not quite right, just trying to figure out what that is. Would love any help here!
I have a file structure that looks like this:
Project (create-react-app)
src
bunch of React code
server
index.js
package.json
package.json
(It's not using next.js. If it were, I'd just use the /pages/api/* files)
In my top-level package.json, I have:
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build && cd server && npm install && npm run start",
}
and in my /server/package.json I have just a simple start command: node index.js
My server/index.js file:
const path = require('path');
const express = require("express");
const PORT = process.env.PORT || 3001;
const app = express();
app.use(express.static(path.resolve(__dirname, '../MyProject/build')));
app.get('/nonce', async (req, res) => {
const { address } = req.query;
const quantity = snapshot[address];
return res.json({ quantity, address }); // for testing
})
Edit:
With this as-is, my build phase never actually completes.. It runs a server at 3001 and that's the last log of the Build log
> MyProject-server#0.1.0 start /vercel/path0/server
> node index.js
Server listening on 3001

Unable to transpile ES6 express server using Parceljs in development mode

I am trying to transpile an ES6 express app using Parceljs.
Trying to run the parcel dev server using yarn parcel index.js displays that it is running at localhost:1234 but the page is blank. It also generates the following output when trying to run node dist/index.js:
index.js:116
throw error;
^
TypeError: Cannot read properties of undefined (reading 'prototype')
Running yarn parcel index.js --target node does not yield any localhost port for me to test the API with. However, the API now works as I can use node dist/index.js to run the script but now I have to resort to npx nodemon /dist/index.js to have file watching.
Here is the sample code.
index.js
import express from "express";
const app = express();
const port = 5000;
app.get("/", (req, res) => {
res.json({ msg: "Hello!" });
});
app.listen(port, () => {
console.log(`Example app listening on port ${port}`);
});
package.json
...
"dependencies": {
"express": "^4.17.3",
"parcel": "^2.3.2",
"parcel-bundler": "^1.12.5"
}
...
I would greatly appreciate a solution that allows me to use Parceljs to watch for file updates directly, preferably with HMR.
See issue 355: Is parcel meant to work with server-side code insluding HMR?: parcel does not (yet) support hot module reloading in nodejs.
parcel creates a web server and serve your code but express need to be called by itself to be able create a web server and server requests.
You'd better use babel & nodemon instead of parcel
I use command bellow
nodemon --exec babel-node src/index.js

Why can't I see my test text on the front page of my original React web app?

As of now, my React app runs on port 3000 via npm start.
I've decided that I want to use MySQL for the web app I'm building via yarn add express mysql.
I made server.js listen in on port 3001.
Whenever I run nodemon server.js and then hit refresh, I'm not seeing test on the front page of my React app (which would indicate that everything works fine).
I can see test if I type localhost: 3001 in my browser but it's completely blank, meaning, I only see test and not the original front page of my web app. It's a whole new different page.
Inside package.json file, I tried to include "proxy":"http://localhost:3001" at the bottom of the file as well as various other places, but it still doesn't work.
How do I make it so that I can see test on the original front page of my web app (port 3000) so I can conclude that everything's working fine and can proceed with integrating MySQL?
Here's my server.js file:
const express = require('express');
const cors = require('cors');
const app = express();
app.use(cors());
app.get('/', (req, res) => {
res.send('test');
});
app.listen(3001, () => {
console.log("listening port 3001");
});
Update
If you don't need to build and try your app in production, meaning you only need to run both of them for development then just use a proxy as suggested in the comments. Run both servers and make requests to your Express API routes on the frontend. You can add a proxy like this in your client's (React part) package.json file.
"proxy": {
"/api/*": {
"target": "http://localhost:3001"
}
}
Then, any request made for /api/* on the frontend goes through your Express server.
For starting both servers at the same time, you can use concurrently. First install it on the server side:
yarn add concurrently
After installing it you add something like this in your scripts part:
"scripts": {
"server": "nodemon index.js",
"client": "npm run start --prefix client",
"dev": "concurrently \"npm run server\" \"npm run client\"",
"prod": "NODE_ENV=production nodemon app.js"
},
I misunderstood your intention at first, this is why I gave an answer like the below one.
This is normal behavior since you haven't configured Express to serve your frontend properly.
First of all, for a React app you don't need any server at all. What you are using right now (on port 3000) is for developing purposes. So, after completing your app you should build it and configure Express to serve it statically.
First, build it:
yarn build
After this step, you will have static files in your client's build directory.
Now, your Express config should be something like this:
const express = require('express');
const cors = require('cors');
const app = express();
app.use(cors());
app.get('/test', (req, res) => {
res.send('test');
});
app.use( express.static( "client/build" ) );
app.get( "*", ( req, res ) =>
res.sendFile( path.resolve( __dirname, "client", "build", "index.html" ) ) );
app.listen(3001, () => {
console.log("listening port 3001");
});
Notice the route change for Express. I changed / with /test. So, when you hit /test you will see what your Express route serves. Other than this route you should see your React app.
Also, don't forget to change those if your setup is different:
client/build
and
path.resolve( __dirname, "client", "build", "index.html" )
This means Express searches a client directory and you React app resides there.
PS: You will only start the Express server, there will be no more server for React since you don't need it to serve with Express.
Also, related part can be enhanced like this:
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" ) ) );
}
So, at runtime you can pass an environment variable and Express hits this route only in production.

Set up proxy server for create react app

I have started a react application using create-react-app and ran the npm run eject script to gain access to all files. I afterwards installed express and created server.js file that sits on same level as package.json file
these are server.js file contents:
const express = require('express');
const app = express;
app.set('port', 3031);
if(process.env.NODE_ENV === 'production') {
app.use(express.static('build'));
}
app.listen(app.get('port'), () => {
console.log(`Server started at: http://localhost:${app.get('port')}/`);
})
Nothing crazy here, just setting up for future api proxies where I need to use secrets and as I don't want to expose my api.
after this I added a "proxy": "http://localhost:3001/" to my package.json file. I am now stuck as I need to figure out how to start my server correctly and use this server.js file in development mode and afterwards in production.
Ideally It would also be good if we could use more that one proxy i.e. /api and /api2
You didn't have to eject to run your server.js. You can just run it with node server.js together with create-react-app.
You can still do npm start even after ejecting to start your dev server.
To run /api1 and /api2, you just have to handle it in your server.js file and it should work just fine. You need to match the port in your server.js and the one in proxy settings inside package.json - in this case, it should be "proxy": "http://localhost:3031"

express' response.sendFile() sends Uncaught SyntaxError: Unexpected token <

I'm using react-router with browserHistory. This function:
app.get('*', function (request, response){
response.sendFile(path.join(__dirname + "/public/index.html"))
})
is supposed to send the Index.html since the routing happens client-side with react-router.
But somehow my index.html is misunderstood by the server and I get this error:
Uncaught SyntaxError: Unexpected token <
I don't know what the problem here is. Is the file path wrong? My tree looks like this:
/app
/app/myJavascriptStuff.js
/public
/public/index.html
/moreStuffThatsNotRelevant
/server.js <- my express file
without the above described function my page usually responds with:
Cannot GET /whatever
on every page refresh that doesn't happen on localhost:3000 (e.g. localhost:3000/whatever)
Because I'm aware that i suck at describing things, here is a link to the repository.
Help is very appreciated. :)
Problem can be because for each request you are sending index.html even when browser asks for your bundle.js or style.css via
app.get('*', function (request, response){
response.sendFile(path.join(__dirname + "/public/index.html"))
});
Define a public folder from where these files can be served let say public(where you have your index.html in your github repo). Let webpack to generate the bundle.js in that folder. Also point in your index.html to use bundle.js from that folder.
Next in your server.js you need to do some changes. Let express to use public path for serving these files when asked by browser.
An example can be -
const app = express();
const publicPath = express.static(path.join(__dirname, 'public'), { redirect : false });
const indexPath = path.join(__dirname, 'public/index.html');
app.use(publicPath);
app.get('/', function (_, res) { res.sendFile(indexPath) });
app.get('*', function (_, res) { res.sendFile(indexPath) });
First of all you did not build your bundle.js file with your webpack. Before you can serve it you need to build it first.
Change you package.json script to
"scripts": {
"build": "webpack --progress --color --config webpack.config.js --watch",
"start": "node server.js"
}
and run the command npm run build before running your server.
If you webpack bundle.js doesn't get created inside /public/build then create a directory build inside public and run the above command again.
This should solve your problem.

Categories

Resources