Lazy loading with Angular Dart

Matan Lurey
4 min readNov 14, 2016

--

A little known fact: Angular Dart has supported lazy loading since 1.0.

What does lazy loading (called deferred loading in Dart) do for you?

  • You can break up your application into small, dependent parts
  • It works on every browser — automatically without polyfills
  • Use fully typed Dart code — even your deferred libraries are typed

Don’t worry — you don’t need any extra plugins, loaders, build steps, or dependencies of any kind. It’s completely built in (albeit, I admit relatively undocumented — we’re working on that).

This tutorial expects you to already be familiar with Dart and Angular Dart.

Getting started

I use a mix of both IntelliJ and Visual Studio code with the Dart plugin. Both are fine for following this tutorial — they use the Dart analysis server to provide static warnings, auto-complete, and more — or you can use your favorite text editor.

Creating a new project

I could start from a totally empty folder, but I’m lazy — let’s use stagehand to auto-generate the scaffolding for a new Dart project. We’ll get a nice file structure setup in seconds:

Creating a new Angular Dart application in about 5 seconds

If you want to copy-paste the commands I used:

$ pub global activate stagehand
$ mkdir angular2_lazy_example
$ cd angular2_lazy_example
$ stagehand web-angular

Let’s get all our dependencies too:

$ pub get

I then opened angular2_lazy_example in IntelliJ:

My newly created Angular Dart application. Isn’t it great?

And to preview my application, I run pub serve:

I preview my code using Dartium while developing

OK, but this is supposed to about deferred loading…

Yes, yes it is. And it’s just as easy as the steps above. Let’s add a new component, ReleaseListComponent — it’s going to download a list of the most recent Angular Dart releases, and display them for us.

Creating our new component

Let’s write release_list_component.dart in our lib/ folder:

import 'dart:html';
import 'dart:convert';

import 'package:angular2/angular2.dart';

@Component(
selector: 'release-list',
templateUrl: 'release_list_component.html',
styleUrls: const ['release_list_component.css'],
)
class ReleaseListComponent implements OnInit {
static const _apiUrl =
'https://api.github.com/repos/dart-lang/angular2/tags';

List<GithubTag> releases = const [];

@override
ngOnInit() async {
final tags = JSON.decode(await HttpRequest.getString(_apiUrl));
releases = (tags as List<Map>)
.map((t) => new GithubTag(t['name'], t['commit']['url']))
.toList();
}
}

class GithubTag {
final String name;
final String url;

GithubTag(this.name, this.url);
}

And let’s add a release_list_component.html:

<ul>
<li *ngFor="let release of releases">
<a [href]="release.url">{{release.name}}</a>
</li>
</ul>

And a release_list_component.css:

ul {
margin: 0;
padding: 0;
}

ul li {
color: #1e90ff;
}

Finally, let’s display the component. Modify app_component.dart:

import 'package:angular2/core.dart';

import 'release_list_component.dart';

@Component(
selector: 'my-app',
styleUrls: const ['app_component.css'],
templateUrl: 'app_component.html',
directives: const [ReleaseListComponent],
)
class AppComponent {}

And app_component.html:

<h1>My First Angular 2 App</h1>
<release-list></release-list>
We’ve added our ReleaseListComponent but it’s not defer loaded yet

Nothing is deferred loaded — yet. Let’s look at our Chrome timeline:

Using dart2js we’ve built and run our application in Chrome.

Splitting out release list

What if we only wanted to load release list after our initial page load? Easy!

Let’s modify our app_component.dart to use DynamicComponentLoader — which allows us to asynchronously load a component by it’s class type.

import 'package:angular2/core.dart';

import 'release_list_component.dart';

@Component(
selector: 'my-app',
styleUrls: const ['app_component.css'],
templateUrl: 'app_component.html',
)
class AppComponent implements OnInit {
final DynamicComponentLoader _loader;
final ViewContainerRef _location;

AppComponent(this._loader, this._location);

@override
ngOnInit() async {
_loader.loadNextToLocation(ReleaseListComponent, _location);
}
}

(I’ve also removed <releases-list> from app_component.html)

Finally, let’s make it actually defer loaded. This is the fun part!

import 'release_list_component.dart' deferred as release_list;@override
ngOnInit() async {
await release_list.loadLibrary();
_loader.loadNextToLocation(
release_list.ReleaseListComponent, _location);
}
A very small code split, but this is just an example.

In just a few minutes, we’ve deferred/lazy loaded our Dart code, HTML template (pre-compiled to Dart code), and related CSS — everything, with a couple lines of code.

Going from here

You’ve seen the most basic example of deferred/lazy loading in Dart. Of course, this also works without Angular Dart, for your own frameworks and projects.

Let me know in the comments or elsewhere if you’d like more information.

Edit: Final code at https://github.com/matanlurey/angular2_lazy_example

--

--

Matan Lurey

Software engineer @Google and @Dart_Lang. Opinionated.