-
Notifications
You must be signed in to change notification settings - Fork 1.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Using Angular , React , VueJS #1818
Comments
@mightytyphoon thank you for starting this discussion. Could you please create a small application showing what have you tried so far, to give us something to start playing with? |
@bajtos Hi, yes sure, here is the repo to clone : https://github.com/mightytyphoon/lb4-ng-quickstart
To make it easy, you just need to type
With the installation of loopback + angular + + the launch of ng serve + ng build watch + lb-tsc --watch + nodemon, there is some wait, but at the end it should work. EDIT : for now it's just angular without router, I'll dig into it today. |
I've added the routing, if the angular app is served on another server than loopback (in my repo localhost:4200) the routing works, which means serving the app only on a CDN and getting datas from the server should works. Now the goal is to serve the angular app with loopback public folder and let it handle the routes. If you try to go directly to localhost:3000/contact it will not work as loopback will throw a 404 error and does not redirect the route to the angular app. But if you use the routerlink in the angular home page it will work. Once this is done I will try to make a server side rendering of the angular app and it should be all good as it will cover all the classic use cases of angular (app served on other server as a browser client or a mobile app client, app served on same server and app served with server side rendering + bonus server side rendering + use of CDN) It means angular should ignore the route going to the api (something like localhost:3000/api/* which should be where the loopback api will handle requests) |
@bajtos Hi again, Actually to make it work, I just need to know how to configure loopback 4 to rewrite unmatched URLs to the index.html. Something like a example.com/api url to handle all REST requests under the /api path It should also be possible to make it work with some rewrite rules and .htaccess but I think doing it with loopback directly is more 'clean'. The loopback 3 equivalent was to catch all routes. in express it's something like this : //configure the order of operations for request handlers:
app.configure(function(){
app.use(express.static(__dirname+'/assets')); // try to serve static files
app.use(app.router); // try to match req with a route
app.use(redirectUnmatched); // redirect if nothing else sent a response
});
function redirectUnmatched(req, res) {
res.redirect("http://www.mysite.com/");
}
...
// your routes
app.get('/', function(req, res) { ... });
...
// start listening
app.listen(3000); Regards. |
So, this code is working, I hope I'm not doing anything wrong with loopback 4 : //in server/src/sequence.ts
async handle(context: RequestContext) {
try {
//first we try to find a matching route in the api
const {request, response} = context;
const route = this.findRoute(request);
const args = await this.parseParams(request, route);
const result = await this.invoke(route, args);
this.send(response, result);
} catch (err) {
//if there is an error, it means no route were matched
//we send the angular app to deal with the unmatched routes,
//if these routes are not matched either, angular app will handle their redirect
//context.response.sendfile('./public/index.html')
////updated from deprecated sendfile to sendFile
context.response.sendFile('public/index.html', {root: './'})
}
} I'm just concerned with security problems, normally angular sanitize anything coming from the url and if no path is matched on the loopback side it's directly given to angular. So it should not be a security problem. What do you think ? A sent token could be ignored on server side maybe ? I will do some tests to see if all is good with (REST requests) params, body, headers.... EDIT : res.sendfile is deprecated, I'm looking into using res.sendFile instead. |
Thank you @mightytyphoon for the example app and further information. I am afraid I won't have time to look into this topic this week. Here is an idea for you to consider: use LB4 as an API router only, create a top-level express app for dealing with your single-page routes & assets, and mount LB4 as a middleware in your express app. See #691 (comment) const mainApp = express();
const apiApp = new MyLb4Application();
mainApp.configure(function(){
mainApp.use('/api', apiApp.requestHandler);
mainApp.use(express.static(__dirname+'/assets'));
mainApp.use(redirectUnmatched);
});
function redirectUnmatched(req, res) {
res.redirect("http://www.mysite.com/");
}
mainApp.listen(3000); The idea is to keep all your API endpoints under I think this is the best option for now, until we figure out how to (re)design LB4 to support single page applications. |
@bajtos Re, this is actually working well : // MY SEQUENCE : server/src/sequence.ts
async handle(context: RequestContext) {
try {
//first we try to find a matching route in the api
const {request, response} = context;
const route = this.findRoute(request);
const args = await this.parseParams(request, route);
const result = await this.invoke(route, args);
this.send(response, result);
} catch (err) {
//this.reject(context, err); <== change this line
context.response.sendFile('public/index.html', {root: './'})
}
} I will dig into your solution, to see if there are better performances using it. |
@mightytyphoon sounds good. I think your sequence is not going to correctly report non-404 errors e.g. validation errors returned when the request body is not a valid model instance. To fix that, you should check if if (err.statusCode === 404) {
context.response.sendFile('public/index.html', {root: './'})
} else {
this.reject(context, err);
} |
In #1848, we reworked the way how static files are served from LB4 apps. We have a "catch-all" route that's invoked when no API endpoints matched the incoming request, and which invokes I can image we could build on top of this design and allow LB4 app developers to specify their own final route handler to invoke when the request did not match any known endpoint or static asset. A mock-up to illustrate my idea: app.finalRoute(context: RequestContext => {
context.response.sendFile('public/index.html', {root: './'});
}); Thoughts? |
A good idea for sure, at a lower priority, IMO. |
Yes this is perfect for a simple app serving. And to finish the very interesting part is the server side rendering. For now using sendFile does the trick and could even be enough in production for a webapp serving customers in a same region. It's not the same if you want your page loaded in less than 1s worldwide. Then you'll need a server side rendering by loopback, different entities running (docker + kubernetes) and a CDN. But as @hacksparrow said it's a lower priority for the project which is in GA for a little more than a month now. Also I think it does not totally rely on loopback dev team, it should be made by community because the team has already a lot to do with authentication, relations, db etc... and optimizations. That's why I propose to work on it when it comes to optimizations in February 2019. But I will be glad to help in any way between now and then. Regards. |
@mightytyphoon We are seeking examples that expand LB functionality from the community. We want to publish them in our docs as Community Contributions. Is it ok with you if we publish a link to: https://github.com/mightytyphoon/lb4-ng-quickstart as an example in loopback.io/docs? |
Hi @bschrammIBM yes of course, if all is working well, it was a really simple quickstart and I didn't do any test to check if it is still working but if it is still working with last loopback 4 version, you have my authorization. I will check that later, if I can make a better quickstart repo. |
I've had a tinker using express to host the loopback app: https://github.com/dougal83/lb4-ng-example (EDIT: link) @mightytyphoon If you have time to review that would be cool. Your repo was a great help. Feel free to provide feedback or reuse. |
@dougal83 nice, to be honest I prefer your solution. My next step is to use Angular Universal with loopback for server side rendering. |
This issue has been marked stale because it has not seen activity within six months. If you believe this to be in error, please contact one of the code owners, listed in the |
This issue has been closed due to continued inactivity. Thank you for your understanding. If you believe this to be in error, please contact one of the code owners, listed in the |
Description / Feature proposal
Serving a web application with built-in router in 3 ways :
Later it could be interesting to handle the rendering on CDNs or to use also CDNs for loopback requests. The goal is to have a high performance delivery service for the user.
Current Behavior
Does not propose a default way to use a routed App such as Angular, React, Vuejs leading to 404 errors.
Expected Behavior
Some tries of mine
I will speak for Angular first even if I think VueJS and React should be really close in the use.
In loopback 3 there was a need to change the middleware and let the angular app handle routes, so if your web application was in a public folder you would need to serve index.html and redirect every routes to the index.html to let Angular deal with these routes.
Here is a post on how to do it : stackoverflow - configure loopback 3 to serve Angular 4+
Now get back to loopback 4.
I think the file to change to let the web app deal with routes is the sequence file :
src/sequence.ts
If I serve the dist folder of a fresh Angular in the public folder I will have some 404 errors from Angular in browser console :
For now I am trying to play with the sequence.ts file to re-send http routes in browser to the angular app like in loopback 3, any help would be appreciated.
Regards.
The text was updated successfully, but these errors were encountered: