George Edwards George Edwards - 3 months ago 118
TypeScript Question

Angular2 Routing in conjunction to Express routing?

My angular2 app's routes don't work when accessed via URL... Express is rendering an error page instead.

So I have one route (

/docs
) which serves some static content and some other static resources, however,
/
is routed to an index.html which is managed by angular 2. So by opening the application root and then clicking various router links I can get to a route e.g.
/tutorial/chapter/1
. However, as that isn't a registered route in my express app, if I refresh the page I get a 404.

I want to be able to type
http://localhost:3000/tutorial/chapter/1
into my browser and get that page. How do I set express to route all undefined routes to angular, and let angular handle the 404?

Here is my app.js:

var app = express();

// html view engine setup
app.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'));

// uncomment after placing your favicon in /public
app.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 content

app.use('/docs', serveStatic('features/docs/public', { 'index': ['index.html', 'index.htm'] }));

app.use('/', routes);

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


module.exports = app;


You can see the full repo here

Here is the routes middleware def:

var express = require('express');
var router = express.Router();

/* GET home page. */
router.get('/', function(req, res, next) {
res.render('index', { title: 'Express' });
});


module.exports = router;

Answer

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 setup
app.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 /app
app.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 SHA
file.processChapters();

// uncomment after placing your favicon in /public
app.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 content

app.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 handler
app.use(function (req, res, next) {
  var err = new Error('Not Found');
  err.status = 404;
  next(err);
});

// error handlers

// development error handler
// will print stacktrace
if (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 user
app.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 ...
Comments