react express Uncaught SyntaxError: Unexpected token < - node.js

I understand this error is not the reason for the failing. It is failing because in my index.html file i have:
<body><noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<script type="text/javascript" src="/static/js/main.f4a49fba.js"></script>
</body>
That script tag src is failing and returning the same file contents as the index.html itself. This causes it to render HTML (hence < unexcpected from <!DOCTYPE html>).
I am trying to have both express server with /graphql and react together. The working solution is using express.static middlewear shown below. Problem is the working solution breaks the /graphql endpoint so I cannot return any data.
app.use(express.static(path.join(__dirname, 'client/build')));
I need to get this working so it first allows the previous enpoints (/graphql) before checking static pages so I am trying to use this:
app.get('*', (req, res) => {
res.sendFile('index.html', { root: path.join(__dirname, 'client/build/') });
});
This is successfully getting pulled back but failing to work because main.f4a49fba.js in the script tag does not want to load. I tried changing it to /client/build/static/js/main.f4a49fba.js but still wont load. This is using a build file for production.
UPDATE:
I replaced my code with below which helped but for some reason even though I have /graphql above this it is still being run when a full address is being run.
app.get('*', (req, res) => {
const link = (req.path == '/' ? 'index.html' : req.path);
const root = path.join(__dirname, 'client/build');
res.sendFile(link, { root: root }, (error) => {
if (error) {
res.sendFile('/', { root: root });
}
});
});
I am getting this now when a graphql request comes in which seems like it is missing the first /graphql and going to my updated function above. It is very strange and sticking the graphql full address at the end of whatever current page I am in.
http://localhost:3000/dashboard/accounts/my.herokuapp.com/graphql 404 (Not Found)

Related

How to return a 404 Not found page in an Express App?

I have an express app, in which I have the following code:
app.get('*', (req, res) => {
res.send('404', {
title: 404,
name: 'James Olaleye',
errorMessage: 'Page not found',
});
});
However, My IDE is warning about this message:
express deprecated res.send(status, body): Use
res.status(status).send(body) instead
And with the above code, My Browser is returning the following payload as a JSON object:
{
"title": 404,
"name": "James Olaleye",
"errorMessage": "Page not found"
}
What I want, is to display a 404 Not found page to the user, how can this be achived?
You have two seperate problem
1: you are using an old way to response to the request insted use this res.status(STATUS_CODE).send(BODY)
2: you are sending a json yet you want to display a 404 page in this case you need to send a html template
so your code should look like this
app.get('*', (req, res) => {
res.status(404).send("<div>404 Not Found</div>");
});
I updated your question a bit to make it clearer for future references.
the method res.send is deprecated, among other things because it's usages is too ambiguous. A server response, can be a lot of things, it can be a page, it can be a file, and it can be a simple JSON object (which you have here).
In your case, when you run res.send(404,{ /*...*/ }), the express app assumes you want to send a JSON object, so it does just that.
There are multiple possible ways, to achieve what you want, but I will stick to the most simple solution.
If you want to display an HTML page, in the most simplest form, you can actually just change your piece of code to do this instead:
app.status(404).send(`<h1>Page not found</h1>`)
This will essentially, show a page, instead of a JSON object.
You can even define the whole HTML file if you like:
app.status(404).send(
`
<html>
<!DOCTYPE html>
<head>
<title>404</title>
</head>
<body>
<h1>James Olaleye</h1>
<h1>Page Not Found</h1>
</body>
</html>
`
)
This would be the fastest way to achieve what you want.
A step further, would be to create an HTML file some where in your app, and to send the HTML file instead.
If your source code looks like this:
/
src/
index.js
htmls/
404.html
<!-- htmls/404.html -->
<html>
<!DOCTYPE html>
<head>
<title>404</title>
</head>
<body>
<h1>James Olaleye</h1>
<h1>Page Not Found</h1>
</body>
</html>
// src/index.js
const express = require('express');
const app = express();
const path = require('path');
const PORT = 3000;
app.get('/', function(req, res) {
const options = {
root: path.join(__dirname, '..', 'htmls')
};
res.sendFile('404.html', options, function (err) {
if (err) {
next(err);
} else {
console.log('Sent:', fileName);
}
});
});
This would allow you to have multiple HTML files which you can send around.
There are like I stated, other options as well, but that would make this answer way too long and out of scope. If you are interested, you can research Using template engines with Express and start with the following link.
Happy coding :)

Relative path to JS file changes when path is /reset_page/jwt.token.here

Application was working fine until I changed this:
app.use(express.static("dist"));
app.get(["/", "/page_1", "/page_2"], api_pages_get);
To this (I added a path on the second line):
app.use(express.static("dist"));
app.get(["/", "/page_1", "/page_2", "/reset_page/:reset_password_token"], api_pages_get);
Now the frontend HTML is not loading the desired JS file as it is referencing this:
http://localhost:3000/reset_page/js/bundle.js
Rather than this:
http://localhost:3000/js/bundle.js
So it is adding a directory to the relative path for some reason.
The specific error message in Chrome dev tools is:
Failed to load resource: the server responded with a status of 404
(Not Found) Refused to execute script from
'http://localhost:3000/reset_page/js/bundle.js' because its MIME type
('text/html') is not executable, and strict MIME type checking is
enabled.
The format of the JWT token is:
eyJhbGciOiJIUzI1TiIsInR5cCI6IkpXVCJ0.eyJ1c2VySWQiOjEsImlhdCI6MTUzNDgzMzgyNn5.M8P0Xt92rKVmOximyyjgFISZc8hGFZA3eQjloRHGksB
Maybe a silly idea, but could the "dots" in the JWT token be confusing express in some way?
Edit
In case it is relevant, I am using the simple templating engine example, as described here:
https://expressjs.com/en/advanced/developing-template-engines.html
res.render('index', { page_html: page_html, page_tagline: page_tagline });
app.engine('ntl', function(filePath, options, callback) {
fs.readFile(filePath, function(err, content) {
if (err) return callback(err)
var rendered = content.toString().replace('#page_html#', options.page_html).replace('#page_tagline#', options.page_tagline);
return callback(null, rendered)
})
})
app.set('views', './views')
app.set('view engine', 'ntl')
The js file is referenced like this in the template file index.ntl:
<script src="js/bundle.js"></script>
It was working fine until I made the change described above.
Had to change this:
<script src="js/bundle.js"></script>
to this:
<script src="/js/bundle.js"></script>
in the template index.ntl file (ie add a forward slash to the path).
Per these answers:
https://stackoverflow.com/a/32673698
https://stackoverflow.com/a/22225942

trying to render two different pages using two different entry points webpack

My webpack is partitioned to produce two outputs...
entry: {
a: './src',
b: './Authentication'
},
devtool: 'source-map',
output: {
path:'/',
filename: 'scripts/[name].js',
publicPath: '/'
},
So one of my html file (login.html) will call...
<script type="text/javascript" src='scripts/a.entry.js'></script>
And the other (index.html) calls...
<script type="text/javascript" src='./scripts/b.js'></script>
Now each of these pages is a different route. Obviously index.html will be the main so in my server I did...
var path = require('path');
...
app.use(express.static(path.resolve('public')));
...
app.get('/', function(req, res){
res.sendFile(path.resolve('public/index.html'));
});
Everything renders find when I test it on local. But now I want to access the second login.html on a different route, I added this...
app.get('/login', function (req, res) {
res.sendFile(path.resolve('public/login.html'));
});
But when I go to localhost:3000/login I get this error...
GET http://localhost:3000/scripts/a.entry.js 404 (Not Found)
The output is not found. Why is this so???
You configured your bundle for login.html to be named “a”, not “a.entry”. Try changing your script tag to:
<script src='scripts/a.js'></script>
(you don't need type="text/javascript" anymore in 2016)

Reloading browser for every routes ( Express + gulp + Browsersync )

I have build a simple express web server generated with express generator as follow:
express test -ejs
Everything is working fine so far and I have the following folder (with a few changes):
What I want to achieve now is that:
- for every file I'm working on in "/routes/*.js" and "./*.js", on save reload the server and the browser
- for every file in "/views" and "/public", on save only reload the browser
for that I have set up a gulp file.js with browser-sync in proxy mode as follow:
var server = require('gulp-develop-server');
var bs = require('browser-sync').create();
(some tasks for checking js and less ...)
var options = {
server: {
path: './bin/www',
execArgv: ['--harmony']
},
bs: {
proxy: {
target: 'http://localhost:5000',
middleware: function (req, res, next) {
console.log(req.url);
next();
}
},
files: ['./public/**/*', './views/*'], // files to watch with bs instantly (.ejs & .css)
logLevel: 'debug'
}
};
gulp.task('start', ['js','less'], function () {
server.listen(options.server, function (error) {
if (!error)
bs.init(options.bs);
});
gulp.watch('./less/*.less', ['less-nonstop']);
gulp.watch(['./*.js', './routes/*.js'], ['restart:forjs']);
gulp.watch('./views/*').on('change', bs.reload);
});
The proxy is working fine and every pages on http://localhost:3000 give me the same page as http://localhost:5000 (my express server is configured to listen on port 5000).
Now my problem is that browsersync doesn't always refresh my browser on reload (even if browser sync gets the reload event) in fact it refresh only when I'm on the first route path specified in app.js. For example if I have the following code in app.js:
app.use('/bonjour', routes);
app.use('/users', users);
Browser-sync will only reload the browser on http://localhost:3000/bonjour, but not on http://localhost:3000/users or any other paths. Even if browser-sync gets the reload event (as I can check in the console log). It seems that when I'm displaying any other pages than the first route specified in app.js my browser is like "disconnected" from browser-sync.
Why is that ? and How could I fix it ?
it seems that browser-sync need a proper html page render to work that's why it wasn't working on the other routes in this case. In fact my error.ejs file was just:
<h1><%= message %></h1>
<h2><%= error.status %></h2>
<pre><%= error.stack %></pre>
Correcting it to:
<!DOCTYPE html>
<html>
<body>
<h1><%= message %></h1>
<h2><%= error.status %></h2>
<pre><%= error.stack %></pre>
</body>
</html>
solved the problem and now the browser sync works on every html pages.

Angular not updating html template variables when served via NodeJS server

This is a bit of a specific question, but I'm at a bit of a loss for an answer.
First, a little background. I've been trying to learn angular, and I wanted to start using Node as the backend. I currently have a working tutorial app that I can run locally that just returns data that is hard coded into the main controller.
When I moved the files to my NodeJS server, it stopped working though. Here is what works:
The files load correctly - there are no console errors, and I can view each of the files in the source (index.html, app.js, maincontroller.js)
The scope exists, and the variables are defined. I put a console.log($scope) inside the mainController.js file, and I can see all of the variables defined correctly.
Non-angular javascript works - I can place alerts outside/inside the mainController, and they all work correctly (also, console.log obviously works)
I am serving the files via a simple Node.js server. I am using express and hbs. I was originally using compression, and 0 cache length, but have since removed those with no change in the result.
The specific issue I'm having is that none of the template variables update. I've simplified it down to the following code for testing. When viewed locally, the page says 'I now understand how the scope works!', when served from Cloud 9, the structure exists, but the {{understand}} variable in the template doesn't work.
index.html
<!DOCTYPE html>
<head>
<title>Learning AngularJS</title>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.min.js"></script>
<script src="js/app.js"></script>
<script src="js/maincontroller.js"></script>
</head>
<body>
<div id="content" ng-app="MyTutorialApp" ng-controller="MainController">
{{understand}}
</div>
</body>
app.js
var app = angular.module('MyTutorialApp',[]);
maincontroller.js
app.controller("MainController", function($scope){
$scope.understand = "I now understand how the scope works!";
});
server.js (Node server on Cloud 9)
var express = require('express');
var app = express();
var hbs = require('hbs');
app.set('view engine','html');
app.engine('html',hbs.__express);
app.configure(function() {
app.set('views', __dirname);
});
//app.use(express.compress());
app.use('/js',express.static(__dirname + '/client/js'));
app.use('/css',express.static(__dirname + '/client/css'));
app.use('/img',express.static(__dirname + '/client/img'));
//router
app.get('/',function(req,res){
res.render('client/index.html');
return;
});
//404 responses
app.use(function(req, res, next){
res.status(404);
// respond with html page
if (req.accepts('html')) {
res.render('client/404.html', { url: req.url });
return;
}
// respond with json
if (req.accepts('json')) {
res.send({ error: 'Not found' });
return;
}
// default to plain-text. send()
res.type('txt').send('Not found');
});
app.listen(process.env.PORT);
console.log('listening on port '+process.env.PORT);
everythin became clear when i read
"Handlebars.js is an extension to the Mustache templating language"
what this menas is that hbs uses {{}} as delimiters as well as angular so the {{understand}} in your html never gets to angular because is first parsed and substituted by hbs. if you want to use hbs with angular youll need to change your delimiters using your angulars $interpolateProvider in your app configuration something like
$interpolateProvider.startSymbol('{/{');
$interpolateProvider.endSymbol('}/}');
You can use \{{understand}} as this will counter your hbs and put your angular on top.

Resources