Getting MEAN: Clean URLs

In the previous section we added Angular routing to our project.  That was a pretty long section but this one will be much shorter.

You may have noticed an “oddity”:

Notice the URL of the page: http://localhost:8080/#!/about.

These kind of URLs are commonly known as “hash bang URLs”, but the technical term is a Fragment identifier.  Without digging into a long winded explanation this was simply the way HTML5 applications worked initially and the main reason was that it was the only way to modify the URL in a browser without actually reloading the entire page.  There are two problems with these kind of URLs:

  1. They does not get crawled by most bots – including Google’s
  2. They are downright ugly

Fortunately, while still being the default in AngularJS, modern browsers provide an API  which will let Javascript update the URL without triggering a reload.

Create git branch

lth@ncpws04:~/src/notes$ git branch html5 
lth@ncpws04:~/src/notes$ git checkout html5 
Switched to branch 'html5'

Update Server

First step is to make the server send the same index.html no matter what unknown requests it receives:

app.get('/*', function (req, res) { 
    res.sendFile('index.html', {root: "./src"}); 
});

Update html

The head section of the index.html must include a base:

<base href="/" target="_self"/>

While we are editing this file, we can also update the links in the menu:

<nav class="navbar navbar-dark bg-primary navbar-expand-md">                                                                                                                                              
     <a class="navbar-brand" href="/">Notes</a>                                                                                                                                                            
                                                                                                                                                                                                                      
     <button class="navbar-toggler" data-toggle="collapse" data-target="#headerbar-collapse">                                                                                                              
        <span class="navbar-toggler-icon"></span>                                                                                                                                                         
     </button>                                                                                                                                                                                             
                                                                                                                                                                                                                      
    <div id="headerbar-collapse" class="collapse navbar-collapse">                                                                                                                                        
        <ul class="navbar-nav">                                                                                                                                                                           
            <li class="nav-item">                                                                                                                                                                         
                <a class="nav-link" href="/about">About</a>                                                                                                                                               
            </li>                                                                                                                                                                                         
        </ul>                                                                                                                                                                                             
    </div>                                                                                                                                                                                                
</nav>

Update application.js

Finally we need to configure angular to use the html5 api:

app.config(['$locationProvider',  
    function ($locationProvider) { 
        $locationProvider.html5Mode({ 
            enabled: true, 
            requireBase: true 
        }); 
    } 
]);

Push to git

lth@ncpws04:~/src/notes$ git commit -a -m "Added html5mode" 
[html5 f47080d] Added html5mode 
 3 files changed, 17 insertions(+), 2 deletions(-) 
lth@ncpws04:~/src/notes$ git push --set-upstream origin html5 
Counting objects: 6, done. 
Delta compression using up to 4 threads. 
Compressing objects: 100% (6/6), done. 
Writing objects: 100% (6/6), 786 bytes | 0 bytes/s, done. 
Total 6 (delta 4), reused 0 (delta 0) 
remote: Resolving deltas: 100% (4/4), completed with 4 local objects. 
To github.com:lbthomsen/notes.git 
 * [new branch]      html5 -> html5 
Branch html5 set up to track remote branch html5 from origin.