UI Bakery Challenges
@nikpoltoratsky



Nikita Poltoratsky
Lead Engineer at Akveo
@nikpoltoratsky

@nikpoltoratsky


tibing/platform-terminal

dev.to/nikpoltoratsky
medium.com/@nik.poltoratsky

@nikpoltoratsky



@nikpoltoratsky

3 AM

Nikita Poltoratsky
Lead Engineer at Akveo
@nikpoltoratsky

@nikpoltoratsky


tibing/platform-terminal

dev.to/nikpoltoratsky
medium.com/@nik.poltoratsky

Agenda
- Code organization
- State management
- Code generation
- Rendering Angular from plain old JSON model
@nikpoltoratsky

Code organization
@nikpoltoratsky

Monorepo for
the great good
@nikpoltoratsky



@nikpoltoratsky

Monorepo for the great good
Pros
- Simple code reuse
- Atomic commits
- Easy dependency management
Monorepo for the great good
@nikpoltoratsky

Simple code reuse

@nikpoltoratsky

Atomic commits

@nikpoltoratsky

Atomic commits












@nikpoltoratsky

Easy dependency management

@nikpoltoratsky

Easy dependency management
Angular V 7
Angular V 6
Angular V 8
+
+
+
=
PAIN
@nikpoltoratsky

Easy dependency management
Angular V 8
Angular V 8
Angular V 8
+
+
+
=
happiness
@nikpoltoratsky

Cons
- It’s easy to introduce tight coupling
Monorepo for the great good
@nikpoltoratsky

It’s easy to introduce tight coupling

@nikpoltoratsky


Nx
@nikpoltoratsky

Nx - dealing with tight coupling
{
"nx-enforce-module-boundaries": [
true,
{
"allow": [],
"depConstraints": [
{
"sourceTag": "ui-components",
"onlyDependOnLibsWithTags": ["ui-components"]
},
{
"sourceTag": "admin",
"onlyDependOnLibsWithTags": ["ui-components", "admin"]
},
{
"sourceTag": "client",
"onlyDependOnLibsWithTags": ["ui-components", "client"]
},
{
"sourceTag": "*",
"onlyDependOnLibsWithTags": ["*"]
}
]
}
]
}
@nikpoltoratsky

Cons
- It’s easy to introduce tight coupling
Monorepo for the great good
Pros
- Simple code reuse
- Atomic commits
- Easy dependency management
@nikpoltoratsky

State management
@nikpoltoratsky

Use NgRX wisely
@nikpoltoratsky


What is NgRx
@nikpoltoratsky


NgRx everywhere!
@nikpoltoratsky


NgRx
NgRx Everywhere!
NgRx everywhere!
@nikpoltoratsky


NgRx everywhere!
@nikpoltoratsky


NgRx everywhere!
@nikpoltoratsky

Refactoring
NgRx with facades!
@nikpoltoratsky


Behavior Subjects!
@nikpoltoratsky


Code generation
@nikpoltoratsky

vast Angular schematics
@nikpoltoratsky


What is Angular Schematics
@nikpoltoratsky

# Create component
ng g component LoginComponent
# Setup component from library
ng generate @angular/material:table
# Update library
ng update @angular/material
We have application model
@nikpoltoratsky

{
component: 'card',
children: [
...
],
properties: {
backgroundColor: 'red',
...
}
}
What Angular Schematics do for UI Bakery?
@nikpoltoratsky

- pages
- components
- template
- Import required modules
- install required packages
- Apply required theme
Rendering Angular from plain old JSON model
@nikpoltoratsky

Reinventing the wheel — custom Angular renderer
@nikpoltoratsky


@nikpoltoratsky

It's me! Reinventing the wheel!
We have application model
@nikpoltoratsky

{
component: 'card',
children: [
...
],
properties: {
backgroundColor: 'red',
...
}
}
Rendering without wrappers
@nikpoltoratsky

- Render without additional HTML elements
- Use flexbox instead of absolute positioning
How to do that?
@nikpoltoratsky

- Iterate through the application tree
- find differences between the current and previous state
- change the state operating Angular Views
Diffing the model
@nikpoltoratsky

class Renderer {
private differ: IterableDiffer;
render(components: Component[]) {
const changes: IterableChanges<Component> = this.differ.diff(users);
changes.forEachOperation((change: IterableChangeRecord<Component>,
previousIndex: number | null,
currentIndex: number | null) => {
if (previousIndex === null) {
// new component appeared
} else if (currentIndex === null) {
// component existed before but it's removed
} else {
// component was moved from one position to another
}
});
}
}
Manipulating Angular Views
@nikpoltoratsky

changes.forEachOperation((change: IterableChangeRecord<Component>,
previousIndex: number | null,
currentIndex: number | null) => {
if (previousIndex === null) {
viewContainerRef.remove(previousIndex);
} else if (currentIndex === null) {
viewContainerRef.createComponent(component, currentIndex)
} else {
viewContainerRef.move(component, currentIndex);
}
});
Agenda
- Monorepo for the great good
- Use NgRX wisely
- UI Bakery is a frontend for the vast Angular schematics
- Reinventing the wheel — custom Angular renderer
@nikpoltoratsky

The End!
@nikpoltoratsky

Questions?
UI Bakery Challenges
By Nikita Poltoratsky
UI Bakery Challenges
- 696