http routing instead of vhost with Angular2? - node.js

I have a nodeJS based web app and I want to have a blog subdomain. This is a static (Hexo Based) blog. So I am currently serving my blog on http://localhost:4000/ and an Angular App on http://localhost:4200/, with a project dir like this:
project
|--------Hexo Blog
| |------all Blog files
|
|--------Angular App
|------all ng2 files
I suppose one approach would be to use an Express app.js and vhost to route the blog subdomain to a different port, a bit like this:
app.use(function (req, res, next) {
if (req.headers.host) {
if (typeof req.headers.host === 'string' && req.headers.host.match(/blog\.myDomain\.com/)) { // a simple url match.
proxy.web(req, res, { target: 'http://0.0.0.0:4000/' }); // hexo is running on this host and you can change it.
} else {
next(); // pass the request to other app.
}
}
});
However, I'd rather not add express and vhost as a dependency if it's not required. Is this something I could do with Angular?

Related

express route and react route have conflict - it is returning api result on heroku

first of all it's working proper in my local but it works the way i don't want on heroku.
I working on a MERN stack app and I have express path same time react router path.
https://test.herokuapp.com/project
in my node.js express side
server.js
--------
/* Router */
import routes from "./routes/index.js"
app.use('/', routes)
/* For Deployment */
if(process.env.NODE_ENV === "production") {
app.use(express.static(path.join(__dirname, './../client/build')))
app.get('*', (req, res) => {
res.sendFile(path.resolve(__dirname, "../client/build/index.html"));
})
}
routes/index.js (it returns project data from mongodb)
---------------
router.get( '/project', ProjectController.getAll);
at the same time i have a another route in my react side
const routers = (isUserAuth, isAdminAuth) => [
{
path: '/project',
exact: true,
element: <Project />
}
]
http://localhost:3000/project
that route when react router redirect with a NavLink working and if page refresh manually still working in my local. But when it comes to heroku platform it's working redirect with NavLink but it doesn't work when refresh the page. When refresh the page as i said it returns project data from express serve nodejs side.
I think it's about the first code block I put above. thanks..

Prevent Angular 6 router from overriding routes defined in Express Server

How do I prevent Angular routing from interferring with routes from an Express Node Server?
I'm setting up some routes ( to node-RED middleware) in my Express server:
server.js
// Serve the editor UI from /red
app.use(settings.httpAdminRoot,RED.httpAdmin);
// Serve the http nodes UI from /api
app.use(settings.httpNodeRoot,RED.httpNode);
// Angular DIST output folder
app.use(express.static(path.join(__dirname, 'dist')));
// Send all other requests to the Angular app
app.get('*', (req, res) => {
res.sendFile(path.join(__dirname, 'dist/index.js'));
});
but in my router module they get always overridden ( with our without the default path redirection)
routing.module.ts
const appRoutes: Routes = [
{
path: "example-page",
loadChildren: "../modules/example/example.module#ExampleModule?sync=true"
},
// Last routing path specifies default path for application entry
/* {
path: "**",
redirectTo: "/example-page",
pathMatch: "full"
},*/
];
I'm only providing this little code because I want to ask in general how do I prevent Angular from interferring with routes defined in an Express server and what is the best practice for routing in an Express/ Node.js + Angular + AspNetCore + Webpack app.
If you're using Angular, then let Angular handle all pages. This code takes care of that and hence angular is handling all routes.
app.get('*', (req, res) => {
res.sendFile(path.join(__dirname, 'dist/index.js'));
});
If you want express to handle some routes instead of angular, handle that route before handling angular route as follows:
app.get('/some-non-angular-path', (req, res) => {
//code to handle this path. once it is handled here, angular won't be involved
//non-angular-paths should come first in the order
});
app.get((req, res) => {
res.sendFile(path.join(__dirname, 'dist/index.js'));
});

Serving multiple react apps with client-side routing in Express

I have different software products for one single service, which needs to be deployed to a single server. The clients are built with react, with a build setup by create-react-app, while the server runs Node.js and Express.
When I serve a single application from the server it is done the following way:
// App.js
// ...
// Entry point for data routes (API)
app.use('/data', indexRoute);
if(process.env.NODE_ENV !== 'development') {
app.use(express.static(path.join(__dirname, 'build-client')));
app.get('/*', function(req, res) {
return res.sendFile(path.resolve( __dirname, 'build-client' , 'index.html'));
});
}
I want to be able to serve multiple apps from the server. How should I do that?
What I tried is to wire in different static paths for the assets and separate the clients with different names, although it did not work. Like this:
// App.js
// ...
// Entry point for data routes (API)
app.use('/data', indexRoute);
if(process.env.NODE_ENV !== 'development') {
app.use(express.static(path.join(__dirname, 'build-client')));
app.use(express.static(path.join(__dirname, 'build-admin')));
app.get('/client/*', function(req, res) {
return res.sendFile(path.resolve( __dirname, 'build-client' , 'index.html'));
});
app.get('/admin/*', function(req, res) {
return res.sendFile(path.resolve( __dirname, 'build-client' , 'index.html'));
});
}
I have also tried to do it this way, but Express throw Error: No default engine was specified and no extension was provided:
if(process.env.NODE_ENV !== 'development') {
// Admin paths
app.use('/admin', express.static(path.join(__dirname, 'build-admin')));
app.get('/admin/*', function(req, res) {
return res.sendFile(path.resolve( __dirname, 'build-admin' , 'index.html'));
});
// Site paths
app.use('/', express.static(path.join(__dirname, 'build-client')));
app.get('/*', function(req, res) {
return res.sendFile(path.resolve( __dirname, 'build-client' , 'index.html'));
});
}
How could I accomplish this or something similar?
After some tinkering I was able to achieve this without using virtual hosts. I used the first idea you gave in the question, except I left the main app at the root (i.e. /).
// when going to `/app2`, serve the files at app2/build/* as static files
app.use('/app2', express.static(path.join(__dirname, 'app2/build')))
// when going to `/`, serve the files at mainApp/build/* as static files
app.use(express.static(path.join(__dirname, 'mainApp/build')))
// These are necessary for routing within react
app.get('app2/*', (req, res) => {
res.sendFile(path.join(__dirname + '/app2/build/index.html'))
})
app.get('*', (req, res) => {
res.sendFile(path.join(__dirname + '/mainApp/build/index.html'));
});
After this, I went into mainApp/package.json and added
"proxy": "http://localhost:4141"
:4141 is the port that the express server is running on. This line will make calls to fetch('/some/route') go back to the server instead of into your react app itself.
Finally, we go to app2/package.json and add
"proxy": "http://localhost:4141/app2",
"homepage": "/app2"
I believe that the key here is the "homepage" key. The way I understand it, when react starts it searches for some static files at its homepage, and without the "homepage" piece I was only able to get either a blank white screen or the mainApp.
I hope this helps someone out there!
EDIT
I have since changed from serving my create-react-apps through my express server to serving them through netlify. Now I don't need to worry about this express setup, or the homepage key in package.json. The express server lives by itself, and the react apps can still both use the same api, and deployment is much easier. Setup with netlify is trivial.
After struggling for a while with this problem I've found a possible solution without compromising the original setup.
We used Express vhost package to setup handling of requests through virtual domains.
When you create your app instance, you should initialize as many apps with express as you want to expose separately (in our case its three separate apps plus the original app instance)
// Create an express instance
const app = express();
const appAdmin = express();
const appClient = express();
const appVendor = express();
After that you need to install vhost and import it. Then with specifying the static folder for each app you can handle serving the static files separately, while the remaining part deals with handling the request for the given subdomains respectively.
appAdmin.use(express.static(path.join(__dirname, 'build-admin')));
appClient.use(express.static(path.join(__dirname, 'build-client')));
appVendor.use(express.static(path.join(__dirname, 'build-vendor')));
appAdmin.use((req, res, next) => {
return res.sendFile(path.resolve( __dirname, 'build-admin' , 'index.html'));
});
appClient.use((req, res, next) => {
return res.sendFile(path.resolve( __dirname, 'build-client' , 'index.html'));
});
appVendor.use((req, res, next) => {
return res.sendFile(path.resolve( __dirname, 'build-vendor' , 'index.html'));
});
app.use(vhost('domain.com', appClient));
app.use(vhost('www.domain.com', appClient));
app.use(vhost('a.domain.com', appAdmin));
app.use(vhost('b.domain.com', appVendor));
Don't forget to add the desired subdomains in your domain's DNS registry. Example:
...records
CNAME vendor #
CNAME admin #

How can I serve my Vuejs front end files from my node/express server?

Basically, I have two routes with express one for the home page and other for the admin page, but I cannot find a good documentation on how to combine Vuejs and Express, so I can serve at the same time both pages assuming that both have different UI's, so the components are not constructed the same.
To use vue-router and avoid running into 404 issues, your express.js has to have a fallback that serves the index.html. Here is a vue guide on how to do it https://router.vuejs.org/en/essentials/history-mode.html
To serve static files with expressjs you need to use the static middleware.
It accepts the directory name as the first argument. This directory shall contain all the static files to be served.
const express = require('express');
let app = express();
app.use(express.static('public')); // NAME OF THE DIRECTORY IS PUBLIC
const serverPort = 3000;
const respHttpOptions = {
root: `public/`,
dotfiles: 'deny',
headers: {
'dina-timestamp': Date.now(),
'my-xxx-header': true
}
};
app.get('/', (req, resp) => { // HANDLE THE REQUEST HERE
resp.sendFile('index.html', respHttpOptions, (err) => {
// SEND INDEX.HTML INSIDE PUBLIC DIRECTORY
if (!err)
console.log(sucL(`Served index.html`));
else
console.log(errL(`Failed to serve index.html ${err}`));
})
});
try {
app.listen(serverPort);
console.log(sucL(`Server started at ${serverPort}`));
} catch (e) {
console.log(errL(e));
}
There is no distinction for vuejs! You could have multiple directories inside the static directory.

Sharing 404 page across node.js apps connected via VHOST

I am sorta new to node.js and web programming in general so excuse if I ask strange questions :D
So here is the way I am setting up my express node.js project.
I have a top level app.js simply to redirect traffic to a few subdomains:
var app = module.exports = express.createServer(options);
app.use(express.vhost('blog.localhost', require('./apps/blog/blog.js')));
app.use(express.vhost('app1.localhost', require('./apps/app1/app1.js')));
app.use(express.vhost('login.localhost', require('./apps/login/login.js')));
In each of the sub-apps, that is included via require(), I simply return a new express server:
module.exports = express.createServer(options);
What is the most elegant way to set up a 404 page? When I was just using a single app, I simply used
app.use(function(req, res, next){
res.render('404', {
});
});
But if I use this method, I am going to have to create a 404.jade for every app and I dislike useless duplications in code. Any idea how to share a single 404 logic across multiple vhosts?
You have 3 hosts that require 3 route files. My suggestion is to require in each this 404 route, from an external file.
This way you would have the 404 route for every host, but it will just reside in one place.
Example:
404 route file - 404.js
module.exports = function (app, req, res, options) {
app.get('/404', function(req, res, next) {
res.render('404', { options: options });
});
}
routes for host A
// define other routes here
...
// you pass the app, req, res as params
// the last param is for local vars sent to the view
require('./routes/404.js')(app, req, res, { host: 'HostA' });

Resources