Angular2 Routing in conjunction to Express routing? Angular2 Routing in conjunction to Express routing? express express

Angular2 Routing in conjunction to Express routing?


Angular 2 assumes that independent of the request URL, the frontend will be returned. This assumption is based on a feature modern browsers implement called push state. You have 3 options if you want to support anything but the bleeding edge of browsers:

  • Recommended: Seperate the API server from the client.
    If you put your client on example.org and your express backend on api.example.org you can just do what Angular assumes to be true. You can also deploy independently and the client can live on a static host or CDN. This will require that you setup CORS though.

  • Catch-All Express Route
    Make sure all your routes in Express differ from the ones you setup in NG2 and make a catch-all handler. Put something like this at the end of your routes/middleware but before the 404 handler!

    app.use(function(req, res, next) {  res.sendFile("index.html");})
  • Use legacy browser-url-styles for the router.
    You can make the NG2 router use hashes for routes. Check here.


app.js

Since order is important and new code is inserted in multiple locations, the whole file is included. Look for comment started with // JS -

var express = require('express');var path = require('path');var favicon = require('serve-favicon');var logger = require('morgan');var cookieParser = require('cookie-parser');var bodyParser = require('body-parser');var serveStatic = require('serve-static')var file = require('./features/prepareTutorial');var routes = require('./ng2/routes/index');var app = express();// html view engine setupapp.set('views', path.join(__dirname, '/ng2/views'));app.engine('html', require('jade').renderFile);app.set('view engine', 'html');app.use(express.static('ng2/views'));app.use(express.static('ng2/public'));app.use('/node_modules', express.static(__dirname + '/node_modules'));app.use('/persist', express.static(__dirname + '/persist'));// JS - Add /appapp.use('/app', express.static(__dirname + '/ng2/views/app'));// I have to comment this line because it failed//file.processTutorial(); //generate html rendered patches for tutorial steps//file.genGit(); //generate git SHAfile.processChapters();// uncomment after placing your favicon in /publicapp.use(favicon(path.join(__dirname, 'ng2/public', 'favicon.png')));app.use(logger('dev'));app.use(bodyParser.json());app.use(bodyParser.urlencoded({ extended: false }));app.use(cookieParser());//all static assetes for hexo contentapp.use('/docs', serveStatic('features/docs/public', { 'index': ['index.html', 'index.htm'] }));//app.use(subdomain('docs', express.static('docs/public')));app.use('/script', serveStatic('features/docs/public/script'));app.use('/style', serveStatic('features/docs/public/style'));app.use('/images', serveStatic('features/docs/public/images'));app.use('/diff', serveStatic('features/tutorial/diffs'));app.use('/git', serveStatic('features/git'));app.use('/chapter', serveStatic('ng2/views/app/tutorial/chapter/chapters'));app.use('/img', serveStatic('features/docs/source/img'));app.use('/config', serveStatic('ng2/config'));app.use('/', routes);// JS - /tutorial static//app.use('/tutorial', express.static('ng2/views/app/tutorial'));// JS - /tutorial/chapter/* send index file app.all(/^\/tutorial$/, (req, res) => {  res.redirect('/tutorial/');});app.use('/tutorial/', (req, res) => {  res.sendFile(__dirname + '/ng2/views/index.html');});// catch 404 and forward to error handlerapp.use(function (req, res, next) {  var err = new Error('Not Found');  err.status = 404;  next(err);});// error handlers// development error handler// will print stacktraceif (app.get('env') === 'development') {  app.use(function (err, req, res, next) {    res.status(err.status || 500);    res.render('error', {      message: err.message,      error: err    });  });}// production error handler// no stacktraces leaked to userapp.use(function (err, req, res, next) {  res.status(err.status || 500);  res.render('error', {    message: err.message,    error: {}  });});module.exports = app;

ng2/config/systemjs.config.js & ng2/public/config/systemjs.config.js

Use absolute path

This is the main issue. With relative path, the browser is requesting files at tutorial/chapter/2/app/*, tutorial/chapter/2/node_modules/*, etc, and the app break down completely.

// snip ...var map = {    'app':                        '/app', // 'dist',    '@angular':                   '/node_modules/@angular',    'angular2-in-memory-web-api': '/node_modules/angular2-in-memory-web-api',    'rxjs':                       '/node_modules/rxjs'  };// snip ...

ng2/views/index.html

Use absolute path

This won't stop the page from loading but a mess.

// snip ...<link rel="stylesheet" href="/stylesheets/style.css">// snip ...


Instead of app.use('/', routes);, register a middleware that will always serve the index.html. Be cautious though, this can cause your app to return index.html even inside the /docs route.

Just use the middleware that renders the index page:

app.use(routes);

Make sure the routes middleware itself always renders the page, not only on / path.

var express = require('express');/* render home page. */var router = function(req, res, next) {  res.render('index', { title: 'Express' });};module.exports = router;

Remove this the 404 handler (it should be automatic)

// catch 404 and forward to error handlerapp.use(function (req, res, next) {  var err = new Error('Not Found');  err.status = 404;  next(err);});

And change the node_modules route to the following (because SystemJS relies on 404 responses during resolution):

var modules = express.Router();modules.use(express.static(__dirname + '/node_modules'));modules.use(function(req, res, next) {    // Missing files inside node_modules must return 404    // for the module loader to work    res.sendStatus(404);});app.use('/node_modules', modules);