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

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.

Related

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

How to add user authentication to docsifyjs

I am using docsifyjs to create a documentation. But I wanted to add Authentication to access the docs.
Basically we serve the docs with following commands
Initializing docsify
docsify init ./docs
After the init is complete, you can see the file list in the ./docs subdirectory.
index.html as the entry file
README.md as the home page
.nojekyll prevents GitHub Pages from ignoring files that begin with an underscore
We can now serve the mark-down files as HTML with following commands.
docsify serve docs
or
cd docs && python -m SimpleHTTPServer 3000
or
npx http-server docs
Here docsify is served by giving the path of initialized directory.
But I am not able to figure out how to serve this with expressJS. So that I can add authentication.
I have tried adding app.js to ./docs and added the following code but markdown files are not being rendered.
var express = require('express');
var path = require('path');
var serveStatic = require('serve-static');
var app = express();
app.use(serveStatic('/', { 'index': ['index.html', 'index.htm'] }));
app.get('/', (req, res) => {
res.sendFile(path.join(__dirname, 'index.html'));
})
app.listen(8000);
Please help. Thanks

filesending for index.html overrides all get apis

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.

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.

Requests for JS and CSS giving index.html instead

I'm using Express and create-react-app.
My React app is a ways along, and now I'm trying to serve it from an Express server.
// server/app.js
const express = require('express');
const path = require('path');
const app = express();
// Serve static assets
app.use(express.static(path.resolve(__dirname, '..', 'build')));
// serve main file
app.get('*', (req, res) => {
res.sendFile(path.resolve(__dirname, '..', 'build', 'index.html'));
});
module.exports = app;
(My build directory is populated when I do npm run build.
I view the page in Chrome, and what happens when loading the page at localhost:3000 is the Console prints Uncaught SyntaxError: Unexpected Token <, and in the Sources tab it shows that the content of my CSS and JS files are simply the same as index.html: as in this image.
This seems like a recognizable issue, so hopefully someone has seen this before. I'm sort of stumped on where to even begin, especially because I was actually serving the app from Express successfully at first. Then this started happening, then it stopped after some random switching of git branches and reverting and replaying changes, and then it started happening again. So I'm not even sure what makes it happen or not happen.
It appears that your app.use(express.static... call is failing, so instead all of the requests (including for the static assets) are being handled by the app.get('*', (req, res) => { part.
As you are intending to use this to serve a React app, I'd suggest taking inspiration from a boilerplate, "to see how it's done". I personally use NYTimes's kyt project and there's react-starter-kit too.
Try the following code changes which are detailed from the express documentation - serving static files in express:
Replace
app.use(express.static(path.resolve(__dirname, '..', 'build')));
With
app.use(express.static('build'))
Remove
app.get('*', (req, res) => {
res.sendFile(path.resolve(__dirname, '..', 'build', 'index.html'));
});
The problem was "homepage": ... in package.json.
When npm run build runs and there is a homepage URL in package.json that has a non-empty path (like a Github Pages URL like this, https://username.github.io/project_name, where "/project_name" is the path), it changes where it expects the files inside /build to be. The requests for my js and css were going to /project_name/static/... instead of /static/....
It even said in the log output of npm run build:
The project was built assuming it is hosted at /project_name/.
You can control this with the homepage field in your package.json.
On my localhost, it wasn't hosted at /project_name/, so the paths were off.

Categories

Resources