×
Copy
Open
Link
Embed
Share
Beginning
This slide
Copy link URL
Copy link URL
Copy iframe embed code
Copy iframe embed code
Copy javascript embed code
Copy javascript embed code
Share
Tweet
Share
Tweet
Slide 1
Slide 1 text
Architectures Scaleable With angular and nx
Slide 2
Slide 2 text
fabiangosebrink.bsky.social Fabian Gosebrink
Slide 3
Slide 3 text
fabiangosebrink.bsky.social Fabian Gosebrink
Slide 4
Slide 4 text
No content
Slide 5
Slide 5 text
No content
Slide 6
Slide 6 text
No content
Slide 7
Slide 7 text
What the F*** is in there???
Slide 8
Slide 8 text
Throwaway Code?
Slide 9
Slide 9 text
Time Pressure
Slide 10
Slide 10 text
No content
Slide 11
Slide 11 text
Testing?
Slide 12
Slide 12 text
No content
Slide 13
Slide 13 text
No content
Slide 14
Slide 14 text
No content
Slide 15
Slide 15 text
Fix bug
Slide 16
Slide 16 text
Fix bug Create a feature
Slide 17
Slide 17 text
Fix bug Create a feature In every app
Slide 18
Slide 18 text
No content
Slide 19
Slide 19 text
No content
Slide 20
Slide 20 text
No content
Slide 21
Slide 21 text
Dependency Management
Slide 22
Slide 22 text
Publish Install Build
Slide 23
Slide 23 text
Different Versions Multiple Apps
Slide 24
Slide 24 text
Pipelines Additional
Slide 25
Slide 25 text
repositories Additional
Slide 26
Slide 26 text
Internal Arch External Deps
Slide 27
Slide 27 text
No content
Slide 28
Slide 28 text
Architectures Scaleable With angular and nx
Slide 29
Slide 29 text
No content
Slide 30
Slide 30 text
Latest Tools
Slide 31
Slide 31 text
No content
Slide 32
Slide 32 text
Modern Techniques
Slide 33
Slide 33 text
No content
Slide 34
Slide 34 text
No content
Slide 35
Slide 35 text
What Are Workspaces?
Slide 36
Slide 36 text
No content
Slide 37
Slide 37 text
No content
Slide 38
Slide 38 text
No content
Slide 39
Slide 39 text
No content
Slide 40
Slide 40 text
No content
Slide 41
Slide 41 text
No content
Slide 42
Slide 42 text
No content
Slide 43
Slide 43 text
No content
Slide 44
Slide 44 text
No content
Slide 45
Slide 45 text
No content
Slide 46
Slide 46 text
No content
Slide 47
Slide 47 text
No content
Slide 48
Slide 48 text
Multiple Apps Multiple Libs
Slide 49
Slide 49 text
Nx CLI
Slide 50
Slide 50 text
Nx CLI
Slide 51
Slide 51 text
Nx CLI
Slide 52
Slide 52 text
Nx CLI
Slide 53
Slide 53 text
No content
Slide 54
Slide 54 text
No content
Slide 55
Slide 55 text
No content
Slide 56
Slide 56 text
No content
Slide 57
Slide 57 text
Rethinking Libraries
Slide 58
Slide 58 text
Libraries
Slide 59
Slide 59 text
Libraries Share Code between Apps
Slide 60
Slide 60 text
Libraries Share Code between Apps Provide Feature to ONe app
Slide 61
Slide 61 text
Libraries Share Code between Apps Provide Feature to ONe app Multiple libs = one feature
Slide 62
Slide 62 text
Features
Slide 63
Slide 63 text
Features Route based
Slide 64
Slide 64 text
Features Route based State based
Slide 65
Slide 65 text
Features Route based State based UI Based
Slide 66
Slide 66 text
No content
Slide 67
Slide 67 text
Feature
Slide 68
Slide 68 text
Feature Container
Slide 69
Slide 69 text
Feature Container Ui
Slide 70
Slide 70 text
Feature Container Ui Domain
Slide 71
Slide 71 text
Feature Container Ui Domain Utils ...
Slide 72
Slide 72 text
Feature Container Ui Domain Utils ... Container Components Presentational Components Models, services, state Utility Functions You name it!
Slide 73
Slide 73 text
No content
Slide 74
Slide 74 text
https://go.nrwl.io/angular-enterprise-monorepo-patterns-new-book
Slide 75
Slide 75 text
Container Ui Vs.
Slide 76
Slide 76 text
@Component({ /* ... */ }) export class MainDoggoComponent implements OnInit { doggoId = input(''); store = inject(DoggosStore); private readonly destroyRef = inject(DestroyRef); ngOnInit(): void { this.store.loadDoggos(this.doggoId()); this.store.startListeningToRealtimeDoggoEvents(); this.destroyRef.onDestroy(() => { this.store.stopListeningToRealtimeDoggoEvents(); }); } rateDoggo(rating: number): void { this.store.rateDoggo(rating); } skipDoggo(): void { this.store.selectNextDoggo(); } selectDoggo(id: string): void { this.store.selectDoggo(id); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
Slide 77
Slide 77 text
@Component({ /* ... */ }) export class MainDoggoComponent implements OnInit { doggoId = input(''); store = inject(DoggosStore); private readonly destroyRef = inject(DestroyRef); ngOnInit(): void { this.store.loadDoggos(this.doggoId()); this.store.startListeningToRealtimeDoggoEvents(); this.destroyRef.onDestroy(() => { this.store.stopListeningToRealtimeDoggoEvents(); }); } rateDoggo(rating: number): void { this.store.rateDoggo(rating); } skipDoggo(): void { this.store.selectNextDoggo(); } selectDoggo(id: string): void { this.store.selectDoggo(id); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 doggoId = input(''); @Component({ /* ... */ }) 1 export class MainDoggoComponent implements OnInit { 2 3 store = inject(DoggosStore); 4 private readonly destroyRef = inject(DestroyRef); 5 6 ngOnInit(): void { 7 this.store.loadDoggos(this.doggoId()); 8 this.store.startListeningToRealtimeDoggoEvents(); 9 10 this.destroyRef.onDestroy(() => { 11 this.store.stopListeningToRealtimeDoggoEvents(); 12 }); 13 } 14 15 rateDoggo(rating: number): void { 16 this.store.rateDoggo(rating); 17 } 18 19 skipDoggo(): void { 20 this.store.selectNextDoggo(); 21 } 22 23 selectDoggo(id: string): void { 24 this.store.selectDoggo(id); 25 } 26 } 27
Slide 78
Slide 78 text
@Component({ /* ... */ }) export class MainDoggoComponent implements OnInit { doggoId = input(''); store = inject(DoggosStore); private readonly destroyRef = inject(DestroyRef); ngOnInit(): void { this.store.loadDoggos(this.doggoId()); this.store.startListeningToRealtimeDoggoEvents(); this.destroyRef.onDestroy(() => { this.store.stopListeningToRealtimeDoggoEvents(); }); } rateDoggo(rating: number): void { this.store.rateDoggo(rating); } skipDoggo(): void { this.store.selectNextDoggo(); } selectDoggo(id: string): void { this.store.selectDoggo(id); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 doggoId = input(''); @Component({ /* ... */ }) 1 export class MainDoggoComponent implements OnInit { 2 3 store = inject(DoggosStore); 4 private readonly destroyRef = inject(DestroyRef); 5 6 ngOnInit(): void { 7 this.store.loadDoggos(this.doggoId()); 8 this.store.startListeningToRealtimeDoggoEvents(); 9 10 this.destroyRef.onDestroy(() => { 11 this.store.stopListeningToRealtimeDoggoEvents(); 12 }); 13 } 14 15 rateDoggo(rating: number): void { 16 this.store.rateDoggo(rating); 17 } 18 19 skipDoggo(): void { 20 this.store.selectNextDoggo(); 21 } 22 23 selectDoggo(id: string): void { 24 this.store.selectDoggo(id); 25 } 26 } 27 store = inject(DoggosStore); @Component({ /* ... */ }) 1 export class MainDoggoComponent implements OnInit { 2 doggoId = input(''); 3 4 private readonly destroyRef = inject(DestroyRef); 5 6 ngOnInit(): void { 7 this.store.loadDoggos(this.doggoId()); 8 this.store.startListeningToRealtimeDoggoEvents(); 9 10 this.destroyRef.onDestroy(() => { 11 this.store.stopListeningToRealtimeDoggoEvents(); 12 }); 13 } 14 15 rateDoggo(rating: number): void { 16 this.store.rateDoggo(rating); 17 } 18 19 skipDoggo(): void { 20 this.store.selectNextDoggo(); 21 } 22 23 selectDoggo(id: string): void { 24 this.store.selectDoggo(id); 25 } 26 } 27
Slide 79
Slide 79 text
@Component({ /* ... */ }) export class MainDoggoComponent implements OnInit { doggoId = input(''); store = inject(DoggosStore); private readonly destroyRef = inject(DestroyRef); ngOnInit(): void { this.store.loadDoggos(this.doggoId()); this.store.startListeningToRealtimeDoggoEvents(); this.destroyRef.onDestroy(() => { this.store.stopListeningToRealtimeDoggoEvents(); }); } rateDoggo(rating: number): void { this.store.rateDoggo(rating); } skipDoggo(): void { this.store.selectNextDoggo(); } selectDoggo(id: string): void { this.store.selectDoggo(id); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 doggoId = input(''); @Component({ /* ... */ }) 1 export class MainDoggoComponent implements OnInit { 2 3 store = inject(DoggosStore); 4 private readonly destroyRef = inject(DestroyRef); 5 6 ngOnInit(): void { 7 this.store.loadDoggos(this.doggoId()); 8 this.store.startListeningToRealtimeDoggoEvents(); 9 10 this.destroyRef.onDestroy(() => { 11 this.store.stopListeningToRealtimeDoggoEvents(); 12 }); 13 } 14 15 rateDoggo(rating: number): void { 16 this.store.rateDoggo(rating); 17 } 18 19 skipDoggo(): void { 20 this.store.selectNextDoggo(); 21 } 22 23 selectDoggo(id: string): void { 24 this.store.selectDoggo(id); 25 } 26 } 27 store = inject(DoggosStore); @Component({ /* ... */ }) 1 export class MainDoggoComponent implements OnInit { 2 doggoId = input(''); 3 4 private readonly destroyRef = inject(DestroyRef); 5 6 ngOnInit(): void { 7 this.store.loadDoggos(this.doggoId()); 8 this.store.startListeningToRealtimeDoggoEvents(); 9 10 this.destroyRef.onDestroy(() => { 11 this.store.stopListeningToRealtimeDoggoEvents(); 12 }); 13 } 14 15 rateDoggo(rating: number): void { 16 this.store.rateDoggo(rating); 17 } 18 19 skipDoggo(): void { 20 this.store.selectNextDoggo(); 21 } 22 23 selectDoggo(id: string): void { 24 this.store.selectDoggo(id); 25 } 26 } 27 ngOnInit(): void { this.store.loadDoggos(this.doggoId()); this.store.startListeningToRealtimeDoggoEvents(); this.destroyRef.onDestroy(() => { this.store.stopListeningToRealtimeDoggoEvents(); }); } @Component({ /* ... */ }) 1 export class MainDoggoComponent implements OnInit { 2 doggoId = input(''); 3 store = inject(DoggosStore); 4 private readonly destroyRef = inject(DestroyRef); 5 6 7 8 9 10 11 12 13 14 15 rateDoggo(rating: number): void { 16 this.store.rateDoggo(rating); 17 } 18 19 skipDoggo(): void { 20 this.store.selectNextDoggo(); 21 } 22 23 selectDoggo(id: string): void { 24 this.store.selectDoggo(id); 25 } 26 } 27
Slide 80
Slide 80 text
@Component({ /* ... */ }) export class MainDoggoComponent implements OnInit { doggoId = input(''); store = inject(DoggosStore); private readonly destroyRef = inject(DestroyRef); ngOnInit(): void { this.store.loadDoggos(this.doggoId()); this.store.startListeningToRealtimeDoggoEvents(); this.destroyRef.onDestroy(() => { this.store.stopListeningToRealtimeDoggoEvents(); }); } rateDoggo(rating: number): void { this.store.rateDoggo(rating); } skipDoggo(): void { this.store.selectNextDoggo(); } selectDoggo(id: string): void { this.store.selectDoggo(id); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 doggoId = input(''); @Component({ /* ... */ }) 1 export class MainDoggoComponent implements OnInit { 2 3 store = inject(DoggosStore); 4 private readonly destroyRef = inject(DestroyRef); 5 6 ngOnInit(): void { 7 this.store.loadDoggos(this.doggoId()); 8 this.store.startListeningToRealtimeDoggoEvents(); 9 10 this.destroyRef.onDestroy(() => { 11 this.store.stopListeningToRealtimeDoggoEvents(); 12 }); 13 } 14 15 rateDoggo(rating: number): void { 16 this.store.rateDoggo(rating); 17 } 18 19 skipDoggo(): void { 20 this.store.selectNextDoggo(); 21 } 22 23 selectDoggo(id: string): void { 24 this.store.selectDoggo(id); 25 } 26 } 27 store = inject(DoggosStore); @Component({ /* ... */ }) 1 export class MainDoggoComponent implements OnInit { 2 doggoId = input(''); 3 4 private readonly destroyRef = inject(DestroyRef); 5 6 ngOnInit(): void { 7 this.store.loadDoggos(this.doggoId()); 8 this.store.startListeningToRealtimeDoggoEvents(); 9 10 this.destroyRef.onDestroy(() => { 11 this.store.stopListeningToRealtimeDoggoEvents(); 12 }); 13 } 14 15 rateDoggo(rating: number): void { 16 this.store.rateDoggo(rating); 17 } 18 19 skipDoggo(): void { 20 this.store.selectNextDoggo(); 21 } 22 23 selectDoggo(id: string): void { 24 this.store.selectDoggo(id); 25 } 26 } 27 ngOnInit(): void { this.store.loadDoggos(this.doggoId()); this.store.startListeningToRealtimeDoggoEvents(); this.destroyRef.onDestroy(() => { this.store.stopListeningToRealtimeDoggoEvents(); }); } @Component({ /* ... */ }) 1 export class MainDoggoComponent implements OnInit { 2 doggoId = input(''); 3 store = inject(DoggosStore); 4 private readonly destroyRef = inject(DestroyRef); 5 6 7 8 9 10 11 12 13 14 15 rateDoggo(rating: number): void { 16 this.store.rateDoggo(rating); 17 } 18 19 skipDoggo(): void { 20 this.store.selectNextDoggo(); 21 } 22 23 selectDoggo(id: string): void { 24 this.store.selectDoggo(id); 25 } 26 } 27 rateDoggo(rating: number): void { this.store.rateDoggo(rating); } skipDoggo(): void { this.store.selectNextDoggo(); } selectDoggo(id: string): void { this.store.selectDoggo(id); } } @Component({ /* ... */ }) 1 export class MainDoggoComponent implements OnInit { 2 doggoId = input(''); 3 store = inject(DoggosStore); 4 private readonly destroyRef = inject(DestroyRef); 5 6 ngOnInit(): void { 7 this.store.loadDoggos(this.doggoId()); 8 this.store.startListeningToRealtimeDoggoEvents(); 9 10 this.destroyRef.onDestroy(() => { 11 this.store.stopListeningToRealtimeDoggoEvents(); 12 }); 13 } 14 15 16 17 18 19 20 21 22 23 24 25 26 27
Slide 81
Slide 81 text
@Component({ /* ... */ }) export class DoggoListComponent { doggos: = input([]); doggoSelected = output(); selectDoggo(doggo: Doggo) { this.doggoSelected.emit(doggo.id); } } 1 2 3 4 5 6 7 8 9 10
Slide 82
Slide 82 text
@Component({ /* ... */ }) export class DoggoListComponent { doggos: = input([]); doggoSelected = output(); selectDoggo(doggo: Doggo) { this.doggoSelected.emit(doggo.id); } } 1 2 3 4 5 6 7 8 9 10 doggos: = input([]); @Component({ /* ... */ }) 1 export class DoggoListComponent { 2 3 4 doggoSelected = output(); 5 6 selectDoggo(doggo: Doggo) { 7 this.doggoSelected.emit(doggo.id); 8 } 9 } 10
Slide 83
Slide 83 text
@Component({ /* ... */ }) export class DoggoListComponent { doggos: = input([]); doggoSelected = output(); selectDoggo(doggo: Doggo) { this.doggoSelected.emit(doggo.id); } } 1 2 3 4 5 6 7 8 9 10 doggos: = input([]); @Component({ /* ... */ }) 1 export class DoggoListComponent { 2 3 4 doggoSelected = output(); 5 6 selectDoggo(doggo: Doggo) { 7 this.doggoSelected.emit(doggo.id); 8 } 9 } 10 doggoSelected = output(); selectDoggo(doggo: Doggo) { this.doggoSelected.emit(doggo.id); } @Component({ /* ... */ }) 1 export class DoggoListComponent { 2 doggos: = input([]); 3 4 5 6 7 8 9 } 10
Slide 84
Slide 84 text
Nx is built on a technology-agnostic core that maintains modular units of code and understands the dependency graph between them. "
Slide 85
Slide 85 text
Dependency Graph
Slide 86
Slide 86 text
No content
Slide 87
Slide 87 text
Demo
Slide 88
Slide 88 text
80 / 20
Slide 89
Slide 89 text
Your Architecture Is a Moving part
Slide 90
Slide 90 text
Your Architecture Is a Moving part It Evolves!
Slide 91
Slide 91 text
nx g @nx/angular:move --project my-lib --destination shared/my-lib
Slide 92
Slide 92 text
Affected
Slide 93
Slide 93 text
No content
Slide 94
Slide 94 text
No content
Slide 95
Slide 95 text
nx affected -t lint
Slide 96
Slide 96 text
No content
Slide 97
Slide 97 text
Buildable Publishable Normal
Slide 98
Slide 98 text
... --buildable ... --publishable
Slide 99
Slide 99 text
Code Quality
Slide 100
Slide 100 text
No content
Slide 101
Slide 101 text
No content
Slide 102
Slide 102 text
App About Doggos Container Container Ui Domain Utils Shared util-environments util-Auth util-Common UI-common
Slide 103
Slide 103 text
App About Doggos Container Container Ui Domain Utils Shared util-environments util-Auth util-Common UI-common scope:about scope:doggos scope:shared
Slide 104
Slide 104 text
App About Doggos container container Ui Domain Utils type:container Shared util-environments util-Auth util-Common UI-common scope:about scope:doggos scope:shared
Slide 105
Slide 105 text
App About Doggos Container Ui Domain Utils type:container type:ui type:domain type:utils Shared util-environments util-Auth util-Common UI-common scope:about scope:doggos scope:shared container type:container
Slide 106
Slide 106 text
App About Doggos Ui Domain Utils type:ui type:domain type:utils Shared util-environments type:util util-Auth util-Common UI-common type:util type:util type:ui scope:about scope:doggos scope:shared Container type:container container type:container
Slide 107
Slide 107 text
No content
Slide 108
Slide 108 text
No content
Slide 109
Slide 109 text
No content
Slide 110
Slide 110 text
No content
Slide 111
Slide 111 text
No content
Slide 112
Slide 112 text
No content
Slide 113
Slide 113 text
No content
Slide 114
Slide 114 text
No content
Slide 115
Slide 115 text
No content
Slide 116
Slide 116 text
No content
Slide 117
Slide 117 text
No content
Slide 118
Slide 118 text
No content
Slide 119
Slide 119 text
No content
Slide 120
Slide 120 text
nx migrate
Slide 121
Slide 121 text
No content
Slide 122
Slide 122 text
No content
Slide 123
Slide 123 text
No content
Slide 124
Slide 124 text
No content
Slide 125
Slide 125 text
No content
Slide 126
Slide 126 text
Thank You