April 2017, Denko Mancheski
workshop #7
Bootstrapping
Component tree (smart and dumb components)
NgModule
Zone
Feature modules
JIT / AOT
To bootstrap an Angular app, we need a module. Since its the entry point of the app (or the first module), it is called "root module"
The root module must have a bootstrap property in which will be defined the first component. This component is the root component in the component tree
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app.module';
platformBrowserDynamic().bootstrapModule(AppModule);
// module.ts
import {NgModule} from '@angular/core';
import {BrowserModule} from '@angular/platform-browser';
import AppComponent from './app';
@NgModule({
imports: [BrowserModule],
declarations: [AppComponent],
bootstrap: [AppComponent]
})
export class AppModule {}
Root module
Bootstrap
Component Tree
An NgModule is a class adorned with the @NgModule decorator function. @NgModule takes a metadata object that tells Angular how to compile and run module code. It identifies the module's own components, directives, and pipes, making some of them public so external components can use them.@NgModule may add service providers to the application dependency injectors.
NgModules consolidate components, directives, and pipes into cohesive blocks of functionality, each focused on a feature area, application business domain, workflow, or common collection of utilities.
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
@NgModule({
imports: [ BrowserModule ],
declarations: [ AppComponent ],
bootstrap: [ AppComponent ]
})
export class AppModule { }
Every Angular app has a root module class. By convention, the root module class is called AppModule
NgModule is used for bootstrapping
You launch the application by bootstrapping the AppModule in the main.ts file.
Dynamic bootstrapping with the just-in-time (JIT) compiler
Static bootstrapping with the ahead-of-time (AOT) compiler
Consider the static alternative which can produce a much smaller application that launches faster, especially on mobile devices and high latency networks.
Because the entire application was pre-compiled, Angular doesn't ship the Angular compiler to the browser and doesn't compile in the browser.
An Angular application consists largely of components and their HTML templates. Before the browser can render the application, the components and templates must be converted to executable JavaScript by the Angular compiler.
JIT compilation incurs a runtime performance penalty. Views take longer to render because of the in-browser compilation step. The application is bigger because it includes the Angular compiler and a lot of library code that the application won't actually need. Bigger apps take longer to transmit and are slower to load.
Compilation can uncover many component-template binding errors. JIT compilation discovers them at runtime, which is late in the process.
You can compile the app in the browser, at runtime, as the application loads, using the just-in-time (JIT) compiler. This is the standard development approach shown throughout the documentation. It's great but it has shortcomings.
The ahead-of-time (AOT) compiler can catch template errors early and improve performance by compiling at build time.
Faster rendering
With AOT, the browser downloads a pre-compiled version of the application. The browser loads executable code so it can render the application immediately, without waiting to compile the app first.
Fewer asynchronous requests
The compiler inlines external HTML templates and CSS style sheets within the application JavaScript, eliminating separate ajax requests for those source files.
Smaller Angular framework download size
There's no need to download the Angular compiler if the app is already compiled. The compiler is roughly half of Angular itself, so omitting it dramatically reduces the application payload.
Detect template errors earlier
The AOT compiler detects and reports template binding errors during the build step before users can see them.
Better security
AOT compiles HTML templates and components into JavaScript files long before they are served to the client. With no templates to read and no risky client-side HTML or JavaScript evaluation, there are fewer opportunities for injection attacks.
When our root module start growing, it starts to be evident that some elements (components, directives, etc.) are related in a way that almost feel like they belong to a library that can be "plugged in".
What if we extract these three elements to their own feature module and then we import it into our root module?
Warning: When it comes to components, pipes and directives, every module should import its own dependencies disregarding if the same dependencies were imported in the root module or in any other feature module. In short, even when having multiple feature modules, each one of them needs to import the CommonModule
Not this time :)
Smart / Container components are application-specific, higher-level, container components with access to the application's domain model
Dumb / Presentational components are components responsible for UI rendering and/or behavior of specific entities passed in via components API (i.e. component properties and events). Those components are more in-line with the upcoming Web Component standard
@Component({
selector: 'app-home',
template: `
<h2>All Lessons</h2>
<h4>Total Lessons: {{lessons?.length}}</h4>
<div class="lessons-list-container v-h-center-block-parent">
<table class="table lessons-list card card-strong">
<tbody>
<tr *ngFor="let lesson of lessons" (click)="selectLesson(lesson)">
<td class="lesson-title"> {{lesson.description}} </td>
<td class="duration">
<i class="md-icon duration-icon">access_time</i>
<span>{{lesson.duration}}</span>
</td>
</tr>
</tbody>
</table>
</div>
`,
styleUrls: ['./home.component.css']
})
export class HomeComponent implements OnInit {
lessons: Lesson[];
constructor(private lessonsService: LessonsService) {
}
ngOnInit() {
this.lessonsService.findAllLessons()
.do(console.log)
.subscribe(
lessons => this.allLessons = lessons
);
}
...
}
Significant size already
No re-usability
Lack of generics
Lack of separation
Lack of maintainability
The problem:
Scenarios:
What if we want to display specific lessons for some course ?
What if we want to use the list of lessons somwehere else ?
import {Component, OnInit, Input, EventEmitter, Output} from '@angular/core';
import {Lesson} from "../shared/model/lesson";
@Component({
selector: 'lessons-list',
template: `
<table class="table lessons-list card card-strong">
<tbody>
<tr *ngFor="let lesson of lessons" (click)="selectLesson(lesson)">
<td class="lesson-title"> {{lesson.description}} </td>
<td class="duration">
<i class="md-icon duration-icon">access_time</i>
<span>{{lesson.duration}}</span>
</td>
</tr>
</tbody>
</table>
`,
styleUrls: ['./lessons-list.component.css']
})
export class LessonsListComponent {
@Input()
lessons: Lesson[];
@Output('lesson')
lessonEmitter = new EventEmitter<Lesson>();
selectLesson(lesson:Lesson) {
this.lessonEmitter.emit(lesson);
}
}
Pros:
We could reuse this component in all of these scenarios, because the lessons list component does not know where the data comes from. The responsibility of the component is purely to present the data to the user and not to fetch it from a particular location.
Conclusion:
= Dumb (presentational) component
import { Component, OnInit } from '@angular/core';
import {LessonsService} from "../shared/model/lessons.service";
import {Lesson} from "../shared/model/lesson";
@Component({
selector: 'app-home',
template: `
<h2>All Lessons</h2>
<h4>Total Lessons: {{lessons?.length}}</h4>
<div class="lessons-list-container v-h-center-block-parent">
<lessons-list [lessons]="lessons" (lesson)="selectLesson($event)"></lessons-list>
</div>
`,
styleUrls: ['./home.component.css']
})
export class HomeComponent implements OnInit {
lessons: Lesson[];
constructor(private lessonsService: LessonsService) {
}
ngOnInit() {
...
}
selectLesson(lesson) {
...
}
}
Pros
Text
Conclusion
This type of component is inherently tied to the application itself, so as we can see it receives in the constructor some dependencies that are application-specific, like the LessonsService. It would be very hard to use this component in another application.
The top level component of our view will likely always be a smart component.
Interaction between smart and dumb components
@Input() and @Output()
BUT, the thing is, its sometimes not that simple because custom events like lesson don't bubble up. So if for example you have a deep tree of components and you want a component multiple levels above to know about the event, the event will not bubble. What if we nest components deeper than 1 level ?
Hello Services
@Injectable()
export class LessonSelectedService {
private _selected: BehaviorSubject<Lesson> = new BehaviorSubject(null);
public selected$ = this._selected.asObservable().filter(lesson => !!lesson);
select(lesson:Lesson) {
this._selected.next(lesson);
}
}
http://blog.angular-university.io/angular-2-smart-components-vs-presentation-components-whats-the-difference-when-to-use-each-and-why/
Definition: an execution context for asynchronous operations. They turn out to be really useful for things like error handling and profiling. But what exactly does that mean?
Zone.js helps Angular to be aware of the things which are executed in the app, in order to update the view automatically. The main usage of zone.js in Angular is for the Change Detection mechanism
A Zone is an execution context that persists across async tasks. You can think of it as thread-local storage for JavaScript VMs.
Conclusion: So, without zones, we don’t get any change detection, so we don’t get any of the nice UI updates that we’d expect!
denkomanceski@gmail.com