Angular 2 routing only works in ng serve but not nodemon - node.js

I'm currently developing angular 2 application. But i'm having a hard time understanding why my routing on works in ng serve and not in nodemon? I've tried out multiple method based on what i've research on but they dont really works like how i thought it would be. (Probably due to my poor understanding)
Method 1
Adding useHash: true in the app-routing.module.ts But this would cause all the URL to have # appear in it. And i'm thinking this is meant for debugging purposes right?
const routes = [
{ path: '', component: sampleComponent1 },
{ path: 'page2', component: sampleComponent2 }
];
#NgModule({
imports: [RouterModule.forRoot(routes, {useHash: true})],
exports: [RouterModule]
})
Method 2
Change app.js to render index whenever error is thrown. This method would not have # in URL but it will always return error like GET /page2 404 1.688 ms - 987 in my console.
app.use(function (err, req, res, next) {
// set locals, only providing error in development
console.log(err.message);
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
res.status(err.status || 500);
res.render('error');
});
So as of now, I'm sticking more to method 2 as the URL does not show # in it, but i'm not sure if method 2 is the correct way to do it. Can someone help me out on this?

The reason this works in development with the Angular CLI is that all routes that don't exist get served as index.html
This allows your Angular application to handle all the routing regardless of what URL was actually requested. Once your application is started in the browser the Angular router (assuming that's what you're using) will read the route information and display the correct route to your user.
There are other answers on here that explain this solution as well depending upon your web server.

Related

Cannot GET /login - It used to work, nothing was changed, now I get this

A corporate partner developed this app--using Node.js and Express.js--which gets used about once a month for demos. In December it worked fine, now when trying to access the app it returns "Cannot GET /login." Running the app on multiple systems has the same result.
I'm at a loss as to where to start troubleshooting; any suggestions would be greatly appreciated.
EDIT 1:
This is the only reference to the /login endpoint:
function gotoLogin() {
window.location.href = window.$data.config.API_SERVER + "/login"
}
After reading Cannot GET /login, I altered the Express.js app as such:
Original:
app.get('/', function (req, res) {
res.render('app-template.njk')
})
Altered:
app.get('/*', function (req, res) {
res.render('app-template.njk')
})
I no longer get "Cannot GET /login," but it adds /login before every endpoint i.e. https://localhost:8080/login/login, which throws off everything else: assets, css, js, etc.

How do I prevent node from logging an exception to the console in my NextJS/Express app?

I have an Express application that runs a blog in a NextJS app, very similar to the example in their repo
I have set it up so that my app runs a query to fetch a blog article, and if the result is empty it throws a NotFoundException.
I catch this exception in my NextJS _error.js file, which is similar to a React error boundary, where I route the user to my 404 page. This part works fine.
The problem I'm having is that this exception is logged to the node console even though I'm not logging it when catching the exception. This pollutes our company's logging software with all our 404's
Is there some node/express setting I'm missing here that prevents the logging of exceptions? Here's my Express process error handler:
process.on('unhandledRejection', (reason, promise) =>
console.error(`Unhandled Rejection at: ${promise}.\nreason: ${reason.stack || reason}`));
I know there is a log there, but the format of the one I want to eliminate is different to this, so I'm confident this is not the source.
I won't pretend to know what's going on, but my best guess is that next.js is logging the error somewhere. I did some digging and it appears there's an error logger in the server code that will log on errors unless a quiet property is set on the server:
https://github.com/zeit/next.js/blob/canary/packages/next-server/server/next-server.ts#L105:
return this.run(req, res, parsedUrl)
.catch((err) => {
this.logError(err)
res.statusCode = 500
res.end('Internal Server Error')
})
Here's the sig and body for the logError function:
private logError(...args: any): void {
if (this.quiet) return
// tslint:disable-next-line
console.error(...args)
}
If you look at the documentation for using the next API with a custom server, it notes the following options object properties that can be passed to the constructor:
The next API is as follows:
next(opts: object)
Supported options:
dev (bool) whether to launch Next.js in dev mode - default false
dir (string) where the Next project is located - default '.'
quiet (bool) Hide error messages containing server information - default false
conf (object) the same object you would use in next.config.js - default {}
When constructing the next object, try passing quiet as true to see if it resolves your issue:
const express = require('express')
const next = require('next')
const port = parseInt(process.env.PORT, 10) || 3000
const dev = process.env.NODE_ENV !== 'production'
const app = next({ dev, quiet: true })
const handle = app.getRequestHandler()
The docs also mentions errors are logged in non-production environments (identified when process.env.NODE_ENV !== 'production'), so I would also check to ensure you're setting NODE_ENV to 'production' when starting your application:
NODE_ENV=production node server.js
I hope this helps!
In express you can setup an ErrorMiddleware.
After all your routes declaration, put
server.use(function(req, res, next) {
handler(req, res).catch(e => {
// use rejected promise to forward error to next express middleware
next(e)
})
});
Like this, when you reject a Promise, next(e) will send your error to next middleware. I usually setup a middleware where i send error, and then i manage all errors in one single function (based on statusCode error,...).

react express Uncaught SyntaxError: Unexpected token <

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)

Node express api routes for multilingual directory like url

Does any one knows an example or could explain here how node.js and express would have to route for a multilanguage site? I'm using i18n-node for translation and folder like routing ( /es/, /de/ , etc ) for different languages. This all are static routes but I also have routes like apiRoutes.route('/user/profile') using 'app' at the begining ( app.get('/app/user/profile') so please consider this in your answer so is NOT necesary route to : app.get('/es/app/user/profile') .
having 15 routes like this now:
app.get('/terms', function(req, res) {
res.render('terms',{
...
});
});
how it have to be set for routes like:
app.get('/es/terms', function(req, res) {
res.render('terms',{
...
});
});
Should I duplicate this routes and add for example a locale for
each like:
app.get('/es/terms', function(req, res) {
res.render('terms',{
...
});
});
Or Should do something like:
if cookie['lang'] && cookie['lang'] is in locales
// then redirect to /:lang/terms
else
// show default language in /terms
if req.headers["accept-language"] && req.headers["accept-language"]
// then redirect to /:lang/terms
else
//show default language in /terms
Or there is another way I should approach this that follows good practices or is better respecting standards?
Miro's Answer in :
How can I get the browser language in node.js (express.js)? says I should use app.all('*', ...
Is this all I need?, ..still, it might have a syntax error or i'm not understanding well this two parts
var rxLocal = /^\/(de|en)/i;
...
app.get(/\/(de|en)\/login/i, routes.login);
thanks in advance
You need to consider 2 things :
1. How get the local :
Accept-Language
The HTTP protocole define the Accept-Language header to manage the local. This is a normalized method. You can access it with the req.acceptsLanguages method of express.
+Normalized
+Natively support by brower
-Not easy to by passe by the end user
Path / Cookies
You can get the local from the path. In express it can be do with a parameter patter like /:local/rest/of/path and retrieve in the request object with the req.param method.
You can also get the information from the cookies with the req.cookies properties (don't forgot to set it).
Both
To increase the user experience you can mix the both method. For exemple get the default language from the HTTP header send by the browser but permite to the user to override this in you application and store this parameter in the cookies.
2. Use the local:
Each methods to get the local can be used from different way. I will
use random of them in exemple but they are all compatible.
Top level configuration.
In case of you use a template Engine and you controller can be local agnostic. You can use a middleware to get the local information and configure the render engine.
app.use('/:local' (req, res, next) => {
let localKey = req.param('local');
res.locals = // Some ingenious method to get the locales from localKey
next();
}
Check res.locals and your engine documentation.
Use it in controller.
If the local is part of the contoller process. You can get directly is value in controller.
In case of you use a complexe method to determine the final value of the local, you can also use a middleware to determine this value and enrich the request with it.
app.use((req, res, next) => {
let local = req.cookies.local;
if(!local) local = req.acceptsLanguages();
if(!local) local = 'en-US';
req.local = local;
}
Both
You can use both method too. It depend of what you need. Find the best way to get a maintainable code and avoid replication for your use case.
When you use middle where witch impact the controllers, be sure you declare them before your routes.
You can use a route parameter to get the locale from the URL, like this:
app.get('/:lang/terms', function (req, res) {
if (req.params === 'es') {
res.send('¡Hola!');
else {
res.send('Hi!');
}
});
The colon character tells Express to put whatever is between the first to slashes of the path in req.params.lang.
See express routing documentation for details.

How to Redirect to Single Page Web App in Express for Node

I am writing a website with a single page web app (the rest of the website is just static files which are served). I am trying to write a piece of middleware for express to redirect all requests that follow the pattern 'example.com/app' to 'example.com/app' so that requests such as 'example.com/app/my/specific/page/' will all result in the same page being sent. The key issue with this is that the url in the address bar of the browser must not change so that the javascript app itself can interpret it and display the correct thing.
I could have done something like this:
app.use( '/app', function ( req, res ) {
res.redirect('/app');
});
However, this causes the url of the page to change and a separate HTTP request is assumedly made.
The most obvious alternative solution is to do something like this:
app.use( '/app', function ( req, res ) {
res.sendfile(__dirname + '/public/app/index.html');
});
The issue here is that resources from the page after requests like 'example.com/app/my/specific/page/' will look in the wrong location. For example, if I have an image on the page such as then it will look for example.com/app/my/specific/page/image.jpg. Since no image is returned, it will not display on the page. This happens for all external scripts or stylesheets.
I also tried something like this:
app.use( '/app', function ( req, res ) {
res.sendfile(__dirname + '/public/beta' + url.parse(req.url).pathname);
});
but that was very stupid of me for obvious reasons.
In the end I used this middleware to serve the app's page when appropriate
// all unmatched requests to this path, with no file extension, redirect to the dash page
app.use('/dash', function ( req, res, next ) {
// uri has a forward slash followed any number of any characters except full stops (up until the end of the string)
if (/\/[^.]*$/.test(req.url)) {
res.sendfile(__dirname + '/public/dash/index.html');
} else {
next();
}
});
I then set used a base HTML element with the href attribute pointed to the root.
If you're still trying to accomplish this I may have found a starting point. Alexander Beletsky has a Backbone.js + Express SPA boilerplate repo Located Here.
For a brief article on how it came about you can read his article on Dzone.

Resources