Software Engineer @ThisDot
pato_codes
devpato
pato_codes
pato_codes
tasks$: Observable<Task[]>;
tasks$: any;
tasks$: Observable<any[]>;
DO IT
DON'T IT
pato_codes
modules, components, directives, services, pipes, and guards
SearchComponent we want to its files search.component.ts, search.component.html and search.component.scss
You can achieve this by using the Angular CLI
pato_codes
pato_codes
2 kinds
App Shared Code
Projects Shared Code
pato_codes
pato_codes
NPM Enterprise Registry
pato_codes
pato_codes
pato_codes
Where search-lib is the name of your library
ng generate library search-lib
pato_codes
PROS
pato_codes
CONS
pato_codes
Monorepos are a source control pattern where essentially all the codebase lives in the same repository. All projects will always use the latest version of the code.
What is a Monorepo?
pato_codes
PROS
microfrontend allows large applications to be split into smaller apps in their own codebase, maybe using a totally different stack, that can be composed. For example, your search component could be written in Angular and the rest of the app in Polymer and React.
pato_codes
pato_codes
pato_codes
npm install -g @nrwl/schematics
npx create-nx-workspace@latest thisdot
Install Nx globally
Create a Nx Workspace
pato_codes
? What to create in the new workspace (Use arrow keys)
❯ empty [an empty workspace]
web components [a workspace with a single app built using web components]
angular [a workspace with a single Angular application]
angular-nest [a workspace with a full stack application (Angular + Nest)]
react [a workspace with a single React application]
react-express [a workspace with a full stack application (React + Express)
pato_codes
? What to create in the new workspace empty [an empty workspace]
? CLI to power the Nx workspace (Use arrow keys)
❯ Nx [Extensible CLI for JavaScript and TypeScript applications]
Angular CLI [Extensible CLI for Angular applications. Recommended for Angular
projects.]
pato_codes
Angular apps go here
Libraries used by your Angular apps go here
pato_codes
Add the capability to create Angular applications via:
ng add @nrwl/angular --defaults
Now create your Angular app
ng g @nrwl/angular:application employees
pato_codes
? Which stylesheet format would you like to use?
CSS
❯ SASS(.scss) [ http://sass-lang.com ]
Stylus(.styl)[ http://stylus-lang.com ]
LESS [ http://lesscss.org ]
? Would you like to configure routing for this application? (y/N) y
pato_codes
pato_codes
ng serve employees
pato_codes
pato_codes
In your command line
ng g @nrwl/workspace:lib employee
Go to libs/data/src/lib/employee.ts
export interface Employee {
id: number;
name: string;
}
pato_codes
import { Employee } from '@thisdot/employee';
Note: If you are using VS Code, restart it
pato_codes
ng g @nrwl/angular:lib ui
pato_codes
libs/ui/src/lib/ui.module.ts
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
@NgModule({
imports: [CommonModule]
})
export class UiModule {}
pato_codes
ng g component employee-list --project=ui --export
pato_codes
import { Component, OnInit, Input } from '@angular/core';
import { Employee } from '@thisdot/employee';
@Component({
selector: 'thisdot-employee-list',
templateUrl: './employee-list.component.html',
styleUrls: ['./employee-list.component.scss']
})
export class EmployeeListComponent implements OnInit {
@Input() employees: Employee[];
constructor() { }
ngOnInit() {}
trackById(employee: Employee) {
return employee ? employee.id : null;
}
}
pato_codes
<ul>
<li *ngFor="let e of employees; trackBy: trackById(e)">{{ e.name }}</li>
</ul>
pato_codes
ng g s employee --project=ui
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Employee } from '@thisdot/employee';
import { Observable } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class EmployeeService {
employees$: Observable<Employee[]>;
constructor(private http: HttpClient) {
this.employees$ = this.http.get<Employee[]>(
'https://my-json-server.typicode.com/devpato/nx-fake-data/employees'
);
}
}
pato_codes
pato_codes
export * from './lib/ui.module';
export * from './lib/employee.service';
pato_codes
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { HttpClientModule } from '@angular/common/http';
import { EmployeeListComponent } from './employee-list/employee-list.component';
@NgModule({
imports: [CommonModule, HttpClientModule],
declarations: [EmployeeListComponent],
exports: [EmployeeListComponent]
})
export class UiModule {}
pato_codes
pato_codes
apps/employees/src/app/app.module.ts
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import { RouterModule } from '@angular/router';
import { HttpClientModule } from '@angular/common/http';
import { UiModule } from '@thisdot/ui';
@NgModule({
declarations: [AppComponent],
imports: [
UiModule,
HttpClientModule,
BrowserModule,
RouterModule.forRoot([], { initialNavigation: 'enabled' })
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule {}
pato_codes
<div class="employees-container">
<img src="../assets/images/logotdm.png" />
<h1>Employees</h1>
<thisdot-employee-list
[employees]="employeeService.employees$ | async">
</thisdot-employee-list>
</div>
pato_codes
import { Component } from '@angular/core';
import { EmployeeService } from '@thisdot/ui';
@Component({
selector: 'thisdot-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent {
constructor(private employeeService: EmployeeService) {}
}
pato_codes
.employees-container {
display: flex;
width: 100%;
height: 100vh;
flex-direction: column;
justify-content: center;
align-items: center;
img {
width: 200px;
}
}
pato_codes
pato_codes
"assets": [
"apps/employees/src/favicon.ico",
"apps/employees/src/assets",
{
"glob": "**/*",
"input": "./libs/ui/src/lib/shared-assets",
"output": "./assets"
}
]
pato_codes
ng serve employees
pato_codes
pato_codes
pato_codes
pato_codes
pato_codes
pato_codes
pato_codes
products$ = this.http.get<Product[]>(this.productsUrl)
.pipe(
tap(data => console.log('Products', JSON.stringify(data))),
catchError(this.handleError)
);
// Combine products with categories
// Map to the revised shape.
productsWithCategory$ = combineLatest([
this.products$,
this.productCategoryService.productCategories$
]).pipe(
map(([products, categories]) =>
products.map(product => ({
...product,
price: product.price * 1.5,
category: categories.find(c => product.categoryId === c.id).name,
searchKey: [product.productName]
}) as Product)
),
shareReplay(1)
);
pato_codes
pato_codes
pato_codes
pato_codes
https://slides.com/patriciovargas/sass/fullscreen
pato_codes
pato_codes
pato_codes
pato_codes
-This Dot Labs
-The Nrwl Team for Nx
-FrontEnd Consulting
-Christian Ludman
-Bálint Mérő
pato_codes
ThisDotMedia
ThisDotLab