Thursday, May 14, 2015

Setting up AngularJS HTML5 Mode in Subdirectories with Nginx

Many companies and developers have websites that consist of several subsections divided by subdirectories. Some of those subdirectories could contain entirely separate Angular apps, where some might use HTML5 mode and others might not. Consider large organizations that have several different web development groups managing a number of sections of a growing website, if these "websites" or subsections use Angular and want to enable HTML5 mode then this document might help.

Angular Setup

In the configuration below I've set up a 'home' route and enabled HTML5 mode in the $locationProvider. I've also enabled the hashPrefix for a future article that will describe what that does, but for now let's keep it enabled. If the Angular app can't find the path requested then it'll redirect to the /error path. Normally we would create a state for that path as well, and provide a template, however to keep the article simple I've ignored that code. The full working Angular example code will be linked at the end of this article.

// Declare App
var app = angular.module('testApp',[
    'ui.router' //this app uses ui.router, also consider ngRoute
]);

//create config
app.config(function testAppConfig($urlRouterProvider, $locationProvider, $stateProvider){

    // Routes for URLs that go nowhere
    // our default route is /home
    $urlRouterProvider.when('/', '/home').otherwise('/error');

    // use the HTML5 History API
    $locationProvider.html5Mode(true)
        // Use ! for spiders and old browsers, looks like /#!/path
        .hashPrefix('!');

    // add necessary states
    $stateProvider.state('home', {
        url: '/home',
        controller: 'mainController',
        templateUrl: 'home.tpl.html'
    });
});

Nginx configuration

The directory structure of our sample website is /var/www/html with a subdirectory of /var/www/html/test. We want the /test directory to be an HTML5 Angular app with its own unique files.

root /var/www/html;

# This is the default location, or the root
location / {
 # First attempt to serve request as file, then
 # as directory, then fall back to displaying a 404.
 try_files $uri $uri/ index.html =404;
}

# This is the subdirectory configuration for the new Angular app
location /test/ {
 # First attempt to serve request as file, then
 # as directory, then fall back to the Angular app.
 try_files $uri $uri/ /test/index.html;
}

Gulp-webserver Proxy Configuration

In this example we use Gulp with gulp-webserver to proxy our web requests to our API servers. The same configuration can be made with Grunt, however I prefer Gulp for its ease of use.

gulp.task('startWebserver', function(){
    var stream = gulp.src('build')
        .pipe(webserver({
            host      : '0.0.0.0',
            port      : 8080,
            livereload: {enable: true, port: 8081},
            fallback  : 'index.html',
            https     : true,
            key       : 'config/grunt-connect/server.key',
            cert      : 'config/grunt-connect/server.crt',
            proxies   : [
                {
                    // redirect API requests to our DEV environment
                    // since we don't run the servers on our local machine
                    source: '/api',
                    target: proxyDomainURL + '/api' // proxyDomainURL is your API server location 
                },
                {
                    source: '/test', // the proxy path for the subdirectory
                    target: 'https://0.0.0.0:8080' // is our running website
                }
            ]
        }));
});

Complete Angular Code

As promised, here's the sample app.

index.html

<!DOCTYPE html>
<html ng-app="testApp">
<head>
  <title>Test App</title>

  <base href="/test/" />
</head>

<body ng-controller="testController as test">
  <div>
   
    <h1>{{title}}</h1>

    <!-- Angular UI Router Directive for template insertion -->
    <div id="content" ui-view></div>
  
</div>

  <!-- AngularJS -->
  <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-router/0.2.14/angular-ui-router.min.js"></script>

  <script>
    (function(){
      // Declare App
      var app = angular.module('testApp',[
        'ui.router'
      ]);
      app.config(function testAppConfig($urlRouterProvider, $locationProvider, $stateProvider){

        // Routes for URLs that go nowhere
        $urlRouterProvider.when('/', '/home').otherwise('/error');

        // use the HTML5 History API
        //TODO: turned off because we're using the /secondaryFlow path in DEV.
        $locationProvider.html5Mode(true).hashPrefix('!');

        $stateProvider.state('home', {
          url: '/home',
          controller: 'mainController',
          templateUrl: 'home.tpl.html'
        });
      });
      
      // Create Controller
      app.controller('testController', function($scope, $rootScope){
        console.log('testController');
        // Data  
        $rootScope.title = "Hello, World!";
      // End Controller  
      });

      app.controller('mainController', function($scope, $rootScope){
        console.log('mainController');
        // Data  
        $rootScope.title = "Home";
      });
      
    // End App  
    })();
  </script>
</body>
</html>

home.tpl.html

<h2>You are now on the home page.</h2>

10 comments:

  1. We never miss a single post from this useful website related to js and angularjs. After attending online Angularjs training, this site worked as a supplementary knowledge to our technical knowledge to the knowledge I gained from my instructors.

    ReplyDelete

  2. Thanks for your great information, the contents are quiet interesting.I will be waiting for your next post.



    Angularjs 2 Development Company

    ReplyDelete
  3. Thanks for sharing this informative information...You may also refer....
    How to migrate from a typical HTML4 page to a typical HTML5 page.
    www.s4techno.com/blog/2016/08/30/html5-migration/

    ReplyDelete
  4. This comment has been removed by the author.

    ReplyDelete
  5. Very Nice Blog…Thanks for sharing this information with us. Here am sharing some information about training institute.
    devops training in hyderabad

    ReplyDelete