Backbone Routers, URLs and Test/Production Web Contexts - backbone.js

In my Backbone application I have a main view that shows previews of posts. When the user clicks on a post, the post is expanded in an overlay and the URL is changed to reflect that post. While the post is expanded the user may do something that triggers a call to the server that needs to happen at the root context. The problem is that when the post is expanded, the server call that needs to happen at the root context happens from the post context instead. Here's the order of operations:
Page is loaded with main view url: http://localhost:8080/my-web-app/
User clicks post, overlay is shown, url updated to: http://localhost:8080/my-web-app/posts/1
User clicks something that triggers a call to server. Url is: http://localhost:8080/my-web-app/posts/1/load, which is wrong.
In the example above, the load operation needs to happen from the root context: http://localhost:8080/my-web-app/load
I've tried changing the url property for my models, collections, etc. to include a leading /, but this removes the "/my-web-app/" context (the url becomes http://localhost:8080/load), which is necessary in my test environment. This would work fine in a production environment, of course.
To get around this, I have set the Backbone.history root option to be "/my-web-app/" and have overridden every url property to be as follows:
url: function() {
(Backbone.history.options.root != undefined ? Backbone.history.options.root : "") + "load";
}
While this approach works, it is a pain in the ass to override every url function like this... not to mention, it feels hacky. It is also totally unecessary code for a production environment. Is there a more elegant way to manage this so that it works in both test and production environments?
Thanks!

Application routing shouldn't differ on dev environment and production. This will always bring trouble at some point.
Assuming you're using Apache server on your localhost, you can make a virtual host of your choice and make /my-web-app/ available on the /.
First, add a domain name to your /etc/hosts file and point it to 127.0.0.1, like that:
127.0.0.1 mywebapphost
and then add a virtual host to your Apache vhosts.conf
<VirtualHost *:80>
DocumentRoot "/Users/someone/Sites/my-web-app/" # absolute directory of your webapp
ServerName mywebapphost
</VirtualHost>
And you're done! Your webapp is available on //mywebapphost:8080 and all routing is identical to your production environment.

I had the problem and after stressing for a while realized that you can use the * as a prefix to your routes to eliminate the problem with the web context:
*posts/1/load
The only downside is that the route resolution needs to do more work but given that it's client side it should be negligible.
While it may be true that your routes shouldn't differ between dev, qa production, I think it's fair to say that a lot of web applications are written to be context agnostic so the client side stuff should follow suit imho.

Related

How to configure Next.js' SSR-Caching to work with Nginx?

Good day, everyone!
There is an "official" Next.js example demonstrating a possible implementation of SSR-Caching.
upd: I should've been more precise. I scrolled through the commit history of the example - it turned out the technique had been drastically different up until a recent commit by #leerob. Take a look at the current version and compare it with what it used to be before the recent commit. Apparently, the older version was meant to work with a custom node.js server, whereas the current one takes advantage of the inbuilt Next.js methods. In this question I refer specifically to the version by #leerob.
Here's the "raison d'etre", as it's stated in one of its commits:
React Server Side rendering is very costly and takes a lot of server's CPU power for that. One of the best solutions for this problem is cache already rendered pages.
How exactly is it supposed to be used? Does it work in conjunction with CDN, does it also work with proxy-caching, like Nginx?
My question is this:
Is there a right way to configure the SSR-Caching technique to work with Nginx's caching?
I'd come up with a somewhat workable solution, but later realized that it doesn't behave as I expected.
Here's the deal:
When there is a CACHE HIT, that is to say, Nginx sent previously rendered page from its cache to the client, the app gets reloaded at the client side. There's a couple of problems with that:
it breaks 'the flow' of SPA (it seems to lack the continuity in rendering pages because of the page's reloading);
it makes the client to load unnecessary data with each request;
the reloading part causes the app to lose its state.
N.B.: you never get this behavior when using SSR (getServerSideProps) only (no proxy-caching).
Here is a schematic example of my current workflow:
The client asks for a resource.
Is it Cached?
YES: Nginx returns a cached page along with accompanying scripts (for that purpose you
have to proxy_pass to '/_next/static')
NO: Nginx proxies the request down to the Next.js, then the page is rendered, cached at the Nginx level and finally reaches the client
Example of Nginx config:
location /products {
### these lines are crucial
proxy_pass http://next:3000;
proxy_cache my_cache;
###
proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
proxy_cache_lock on;
proxy_cache_background_update on;
proxy_ignore_headers "Set-Cookie";
add_header X-Cache-Status $upstream_cache_status;
proxy_hide_header X-Powered-By;
}
###static assets
location /_next/static {
proxy_pass http://next:3000;
}
The caching itself works, but how do you make it work properly, without reloading the page?
Are there any workarounds? Or is the described behavior inevitable?
Any help would be much appreciated

Is it OK settings location.href to force routing on the server-side?

I'm working on a React web app with an Asp.Net Core + Typescript back-end. The routing is on the front-end, managed by the React-Router v4. Everything is working fine so far.
By the way, there are cases where I need (I want) to redirect the routing by the server instead to let it to the browser logic. For instance, I want to force the redirection to a certain page when a cookie is not present or expired.
As just for instance, if I use something like <Redirect to="/reserved" /> the React.Router does its best: routes toward the "reserved" page, but that's not what I want. I need this path supplied to the server, i.e. kind of bypassing the front-end routing.
In such cases, the solution I found is to set the desired path as follows:
window.location.href = '/reserved';
That seems sending the new path request straight to the server with no (apparent) involvement with the React.Router. Apparently, everything works fine, as I expect.
The question is: is it a reliable way to achieve the desired behavior, or it looks much likely a hack (and I should avoid it)?
Within the context of a single-page application (SPA), regardless of the framework or technology you are using, setting window.location explicitly is a perfectly fine way to leave the routing control of the SPA and force the browser to make an actual HTTP request for that new route.
Doing so of course means that the whole page will unload, so when doing that, you are leaving your SPA. If that target URL then loads the same SPA again, this will usually be distracting to the user. That is why common SPA router implementations will intercept route changes and handle them through their own routing instead of having the browser make an actual request.
You should check your router’s documentation to see if you can add some router guards that allow you to verify things on load or on route changes, so you can navigate the user away to some forced location.
If that target URL is not part of the SPA, then of course setting window.location is perfectly fine. It’s certainly not a hack but rather just the proper way to change the location without going through the SPA’s router.

How to Offset Angular Application's URL

I have an angular application which looks like this in terms of the directory structure
index.html
libs/
apps/
feature1/
directive.js
view.html
feature2/
feature3/
The application runs in the root of the domain, i.e when you access http://localhost:8080/ the app loads. And other features are accessible in the following url scheme
http://localhost:8080/#/feature1
http://localhost:8080/#/feature2
http://localhost:8080/#/feature3
But now we are going for production setup (which I don't control much) and we also need a landing page. In the new scheme I want the application to load and run at http://production-domain.com/app. Please notice the "app" postfix. The root of the domain will serve only the landing page which will have no business with angular or the application itself. If will just have a link to http://production-domain.com/app. The new url scheme for features should look like this
http://production-domain.com/app/#/feature1
http://production-domain.com/app/#/feature2
http://production-domain.com/app/#/feature3
The application has a lot of view files (templateUrl stuff) and also lot of libs gets loaded through the index.html page. Essentially now the server will be running one level above compared to the current setup.
What is the least intrusive (DRY) way of offsetting the whole angular app to any domain postfix. I don't want to the change the templateUrl path in all the directives.
To do what you are asking, you need to create a sub-folder in the root of your web server called "app". Then move the entire application in the sub-folder. That should be the end of it - meaning you do not have to do anything else and everything should work (given your assets use relative paths to the index.html, otherwise you have to change those).

How can I properly use HTML5 url with AngularJS?

I'm pretty new with AngularJS and server config stuff, and this is a problem I haven't found a satisfactory solution so far.
I would like to be able to use the HTML5 url on a website (without hashbangs), so that I could use addresses like "mydomain/contact" to navigate (I'll stick with the "contact" example for simplicity).
To do that, as I've found so far, one should do two things:
Enable HTML5 on the client side
Enable the HTML5 format on the app/app.js file (also adding the dependency)
$locationProvider.html5Mode(true);
It makes possible to click on links and get the proper url. Still, it doesn't allow someone to access directly the HTML5 url. To get to the "contact" page, I still can't directly access "mydomain/contact" (we get a 404) and I know it makes sense. To solve this, it is still necessary to implement something server-side.
Server-side config
Configure the server to respond with the right file, i.e., I should configure the server to make it respond the same way when I request "mydomain/#/contact" and "mydomain/contact".
The last item is where I'm stuck. I've found many answers like this: "you should configure your server" (they assume the reader already knows how to do this. I don't), but I can't find a complete example on how to do that or where to put any needed files.
I'm using AngularJS 1.6.x and npm 3.10.9 (npm start). My question is: is there any complete example on how to fully use HTML5 urls with AngularJS?
The only problem that exists is that angular can't handle requests it doesn't receive. You need some catch-all so that all routes (/contact etc) are passed to your main index-file.
When you say .htaccess I assume apache. Even so I'd still put nginx in front of apache since it's lightweight and easy to configure (at least compared to the apache behemoth). Sorry, I know that is a very opinionated answer. Anyway with nginx the entire config could look like this:
# usually this file goes in /etc/nginx/conf.d/anyfilename.conf
# but it might vary with os/distro.
server {
listen 80
root /var/www/myapp;
location / {
try_files $uri $uri/ index.html;
}
# And if you want to pass some route to apache:
location /apache {
proxy_pass http://127.0.0.1:81; # Apache listening on port 81.
}
}
I'm sure the same can be achieved with apache alone, but I couldn't tell you how. But perhaps this can be of help: htaccess redirect for Angular routes
There are so many silly toolpacks and utilities I've wasted time learning in my life, but nginx is the one tool I'll never regret I picked up.

Recommended nginx setup for AngularJS as front end and Symfony2 as back end

I want to use Symfony2 as back end to create a REST API and use AngularJS as front end. The 2 are completely separated ie Symfony 2 will not render anything, it'll just send json data to AngularJS.
I'm not sure on how to configure my web server (nginx).
The Symfony documentation gives the configuration but it's intended for a site that only uses Symfony, and so everything outside of the /web/ folder is not accessible.
I can see several possibilities:
Create 2 different directories (eg /path/frontend and /path/backend) and a corresponding website for both. I would then have 2 different addresses to access the front end and the back end (eg http://myfrontend.com and http://mybackend.com). The problem I see is that I probably won't be able to directly use AJAX calls in AngularJS.
Create 2 different directories (eg /website/frontend and /website/backend) and only one website. I would then probably need to access the front end and back end with something like http://example.com/frontend and http://example.com/backend. I'm not sure how to configure the web server though (issue with root /website/backend/web).
Put the AngularJS directory inside the web folder of Symfony, but then I'd need to also change the configuration so that nginx doesn't only server app.php, app_dev.php and config.php.
Put the AngularJS directory in the src folder of Symfony, and have Symfony handle the routing. I don't know if it will mess with AngularJS' one routing. Also I will probably have a few other php that should be accessible, so I'd need to route them through Symfony also.
What would you suggest and why? Maybe I'm missing something obivous?
I guess you could accomplish your task using any of those methods. It would come down to how you want to structure you application and what it's objectives are. For large scale projects the first method (having the API separate from the AngularJS) would serve you well. Twitter really made that software model big.
So I would suggest going with method one. All you would have to do is specify an Nginx header in your server block that allows cross domain access to another domain. So you would specify the following directive in your frontendangular.com site:
add_header Access-Control-Allow-Origin backendsymfony.com;
This way every time a page request comes in on your front end app Nginx tells the browser that it is safe to access another domain (your symfony setup).
These are 2 frameworks that both have powerful routing capabilities, and it looks like you are going for a best of both worlds. There are many pros and cons to any setup, so I'll list a few that come to mind:
Angular routing / templating is great but it will leave you with SEO and meta issues to solve . It's probably better to manage your major pages with symfony2 and any routing within each page with angular. This would allow you to still make dynamic pages w/out compromising your meta and SEO control. Access Control seems flexible but probably not necessary, I would just put all calls to REST API under http://www.thesite.com/api and if I need another setup something like https://api.thesite.com, nginx can route or proxypass this without leaving the domain.
Locating partials gets a little wonky but that's probably fine for a large application. Just note that you will probably need to search the js location object for [host] / [path] /web/bundles/someBundle/public/blah.... Or you can setup a '/partials' path in nginx.
Twig and Angular tpl may end up a confusing mix as they both use {{foo}}. This alone would make me reconsider mixing the 2, and I might look to go with a frontend server, like node with ejs where I could also benefit from the streaming transfer of the data sent from the API.
You can get around it easy enough with but it's still concerning:
angular.module('myApp', []).config(function($interpolateProvider){
$interpolateProvider.startSymbol('[[').endSymbol(']]');
}
);
You do get the benefit of angular partials as symfony twig, which can be good or bad depending on how you see the flexibility being used. I have seen guys making examples of forms that fill out values with symfony data, but they are just undermining the power of angulars binding.
Don't get me wrong, I actually do really like the idea of the two harmonizing.
Just food for thought - cheers

Resources