Lazy loading is a design pattern used to defer loading of resources or components until they are actually needed. In the context of AngularJS applications, lazy loading allows you to load views and their associated controllers only when they are required, which can significantly improve the performance of your web application, especially when dealing with a large number of views or components.
In this guide, we will walk through how to implement lazy loading of views using UI Router in AngularJS, which allows you to load views on demand and reduce the initial loading time of your application.
Step 1: Install and Set Up AngularJS and UI Router
Make sure that you have both AngularJS and UI Router configured in your application. You can include them via CDN or as dependencies in your project.
Here’s a basic HTML setup with the required libraries:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>AngularJS Lazy Loading</title>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.8.2/angular.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-router/0.4.2/angular-ui-router.min.js"></script>
</head>
<body ng-app="lazyApp">
<div>
<a ui-sref="home">Home</a> |
<a ui-sref="about">About</a> |
<a ui-sref="contact">Contact</a>
</div>
<div ui-view></div>
<script src="app.js"></script>
</body>
</html>
Step 2: Create the AngularJS Module and Configure Routes
In your app.js
file, you need to configure the routes and enable lazy loading for the views. The idea is to use the resolve
property to defer loading of the controllers and templates until a specific route is accessed.
Here’s an example setup:
var app = angular.module('lazyApp', ['ui.router']);
app.config(function($stateProvider, $urlRouterProvider) {
// Default route if the URL doesn't match any state
$urlRouterProvider.otherwise('/home');
// Define the states (views)
$stateProvider
.state('home', {
url: '/home',
templateUrl: 'home.html',
controller: 'HomeController'
})
.state('about', {
url: '/about',
templateUrl: 'about.html',
controller: 'AboutController',
resolve: {
// Lazy loading the controller and template for the About page
loadAboutModule: function($q, $timeout) {
var deferred = $q.defer();
$timeout(function() {
deferred.resolve();
}, 1000); // Simulating network delay
return deferred.promise;
}
}
})
.state('contact', {
url: '/contact',
templateUrl: 'contact.html',
controller: 'ContactController',
resolve: {
loadContactModule: function($q, $timeout) {
var deferred = $q.defer();
$timeout(function() {
deferred.resolve();
}, 1500); // Simulating network delay
return deferred.promise;
}
}
});
});
Step 3: Create the Controllers and Views
In your AngularJS application, each route (view) will have a controller associated with it. The controllers for home
, about
, and contact
are loaded lazily when each state is activated.
- home.html
<div>
<h1>Home Page</h1>
<p>Welcome to the home page!</p>
</div>
- about.html
<div>
<h1>About Us</h1>
<p>We are a company that focuses on innovation.</p>
</div>
- contact.html
<div>
<h1>Contact Us</h1>
<p>Feel free to reach out to us at contact@company.com.</p>
</div>
- HomeController, AboutController, and ContactController
app.controller('HomeController', function($scope) {
$scope.message = "Welcome to the Home Page!";
});
app.controller('AboutController', function($scope) {
$scope.message = "This is the About Page!";
});
app.controller('ContactController', function($scope) {
$scope.message = "This is the Contact Page!";
});
Step 4: Lazy Loading Controllers and Templates
Now, let’s implement the lazy loading of controllers and templates in a more efficient manner. Instead of loading everything upfront, we can load the necessary templates and controllers when each state is activated. Here’s how you can do it using the resolve
property:
app.config(function($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise('/home');
$stateProvider
.state('home', {
url: '/home',
templateUrl: 'home.html',
controller: 'HomeController'
})
.state('about', {
url: '/about',
templateUrl: function() {
return 'about.html'; // Lazy loading template for about
},
controller: function($q, $timeout, $state) {
var deferred = $q.defer();
$timeout(function() {
deferred.resolve();
}, 1000); // Simulating network delay for controller
return deferred.promise.then(function() {
return 'AboutController';
});
}
})
.state('contact', {
url: '/contact',
templateUrl: function() {
return 'contact.html'; // Lazy loading template for contact
},
controller: function($q, $timeout, $state) {
var deferred = $q.defer();
$timeout(function() {
deferred.resolve();
}, 1500); // Simulating network delay for controller
return deferred.promise.then(function() {
return 'ContactController';
});
}
});
});
Step 5: Use ui-router
‘s resolve
for Asynchronous Loading
In the previous code snippet, we used resolve
to load controllers and templates asynchronously. In the case of larger applications, especially those with a significant number of views, this technique reduces the initial loading time by deferring the loading of components.
app.controller('AboutController', function($scope) {
$scope.message = "This is the About Page!";
});
app.controller('ContactController', function($scope) {
$scope.message = "This is the Contact Page!";
});
Step 6: Optimize Lazy Loading with Bundle Splitting
For better optimization in larger AngularJS applications, you can split your JavaScript files into smaller chunks and load them lazily. This is useful when your application grows beyond a certain size, and you want to ensure that only the necessary files are loaded for each view. Tools like Webpack or RequireJS can help in achieving this.
For example, with Webpack, you can define entry points for each module and then dynamically load them as needed:
module.exports = {
entry: {
home: './home.js',
about: './about.js',
contact: './contact.js'
},
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist')
},
module: {
rules: [
{
test: /\.js$/,
use: 'babel-loader'
}
]
}
};
Step 7: Final Thoughts
Lazy loading in AngularJS helps improve the performance of your web applications by reducing the initial load time and loading resources only when they are needed. This technique is especially useful for applications with multiple views or components. By combining UI Router, resolve property, and asynchronous loading, you can build more efficient AngularJS applications.