Bhushan Gadekar
Bhushan Gadekar

Reputation: 13805

How to configure loopback to serve angular4 App?

I have generated a LoopBack project and Angular4 project using angular-cli. My LoopBack project serves html files at port 3000 and my Angular4 project is being served at 4200.

Now I need to know if I can serve this angular app on 3000 just like serving static files from LoopBack directory?

What I am trying to ask is if it is possible to use LoopBack server to serve Angular4 app just like it serves Angularjs app?

Thanks

Upvotes: 2

Views: 4387

Answers (3)

Muhammad Arqam
Muhammad Arqam

Reputation: 129

I spent a complete day to resolve this issue. Actually you need to do just two things.

  1. Add the below object in the middleware.json file of your node app.

    "files": { "loopback#static": { "params": "$!../client/" } }

NOTE: you can also give the path of your "dist" folder than "client" folder.

  1. Delete or comment the code of root.js file in the boot folder of your node app.

Upvotes: 0

Janpan
Janpan

Reputation: 2274

Angular only runs on port 4200 if you serve it with the angular-cli using ng serve.

You have to point your angular middleware.json files option to your dist directory of your angular2 app or copy your dist directory contents into your loopback "client" folder.

So it will look something like this :

middleware.json

   .
   .
    "files": {
        "loopback#static": {
          "params": "$!../client/"
        }
      }
   .
   .

The dist directory is where angular outputs your files when you run

ng build

Make sure you don't have a router.js file in your loopback boot folder. This usually holds some route code to redirect the root url to a status output of your api, thus / will take you to your api status instead of your angular app's index.html.

Loopback serves the angular app, however, when you try to access the links directly, e.g. /blog/:id in other words something like /blog/f24382f3y23f9832 then it will fail because loopback does not know how to handle those links and even though loopback client points to angular, angular has not yet "bootstrapped" when querying those links directly.

To fix this, you will have to add custom middleware to redirect loopback to your angular index so that angular's router can take it from there.

So in your middleware.json file, change the following :

"final": {
    "./middleware/custom404": {}
    }

Then add a file custom404.js inside /server/middleware/ so that the full path is /server/middleware/custom404.js . If the middleware directory does not exist, create it.

Then inside the custom404.js file :

'use strict';
module.exports = function () {
    var path = require('path');
    return function urlNotFound(req, res, next) {
        let angular_index = path.resolve('client/index.html');
        res.sendFile(angular_index, function (err) {
            if (err) {
                console.error(err);
                res.status(err.status).end();
            }
        });
    };
};

This will redirect back to your angular app and angular's router will route the url correctly while still being served by loopback.

I use path.resolve so that the link is first resolved according to our web path and not the current directory, else it will be considered as a malicious call and you will receive 403 errors.

I have read the angular.io docs and this is the correct way to implement this. See here angular.io docs . Read the part that is titled "Routed apps must fallback to index.html"

I have made a post of my own here Rewrite requests from loopback to angular2 (Refused to execute script because its MIME type ('text/html') is not executable) where I had a similar problem.

Upvotes: 14

MrTorture
MrTorture

Reputation: 819

I'm assuming you're asking about a production environment. My current Angular setup includes ui-router with html5Mode enabled, so to have Loopback serve static content (and avoiding to introduce an Nginx instance or something similar to do so) I had to remove the static middleware from middleware.json (everything under "loopback#static" key) and make loopback selectively pass through requests to its Api or respond with the corresponding file, in server/server.js and assuming my client was built in client-dist under project's root:

const staticRoot = path.resolve(__dirname, '..', 'client-dist');

app.all('/*', function(req, res, next) {
    // Everything starting with /api passes through
    if (req.url.startsWith('/api')) {
        return next();
    }

    let isAsset = req.url.match(/\/(.*\.(js|css|map|png|svg|jpg|xlsx))\??/);
    if (isAsset) {
        return res.sendFile(isAsset[1], {root: staticRoot });
    }
    // Just send the index.html for other files to support HTML5Mode
    res.sendFile('index.html', { root: staticRoot });
});

If you don't want to use html5Mode, just make loopback#static point to the directory where your client was built, just as described in https://loopback.io/doc/en/lb3/Add-a-static-web-page.html .

For my development environment I just tell the Loopback SDK to use localhost:3000:

.config(function(LoopBackResourceProvider, $windowProvider) {
    'ngInject';
    var $window = $windowProvider.$get();
    if ([4200].includes(parseInt($window.location.port, 10))) {
        LoopBackResourceProvider.setUrlBase(
            'http://' + $window.location.hostname + ':3000/api'
        );
    }
})

Upvotes: 0

Related Questions