Santosh Yadav
GDE for Angular, GitHub Star, Auth0 Amabassador
Co-founder This is Learning
Use TrackBy with ngFor
OnPush Change Detection
Signals
@Component({
selector: 'app-product-signal',
templateUrl: './product-signal.component.html',
styleUrls: ['./product-signal.component.scss'],
standalone: true,
imports: [JsonPipe, CommonModule],
})
export class ProductSignalComponent implements OnInit {
product = signal<Product[]>([]);
addProduct() {
this.product.set(
[{
id: crypto.randomUUID(),
name: 'product 1',
price: 100,
description: 'test',
}]
);
}
}
How Lazy Loading Helps
Seperate feature bundles
Load bundles on demand
Serve less code on first serve
Configure lazy-loading with Module
const routes: Routes = [
{
path: 'rooms',
loadChildren: () =>
import('./rooms/rooms.module').then((m) => m.RoomsModule),
canActivate: [LoginGuard],
canLoad: [LoginGuard],
}
];
Configure lazy-loading with Standalone Component
const routes: Routes = [
{
path: 'rooms',
loadComponent: () => import('./comment/comment.component').then((m) => m.CommentComponent),
canActivate: [LoginGuard],
canLoad: [LoginGuard],
}
];
Avoid Shared Module
Text
import { NgModule } from '@angular/core';
import { OverlayModule } from '@angular/cdk/overlay';
import { CdkTreeModule } from '@angular/cdk/tree';
import { PortalModule } from '@angular/cdk/portal';
import { MatAutocompleteModule } from '@angular/material/autocomplete';
import { MatButtonModule } from '@angular/material/button';
import { MatButtonToggleModule } from '@angular/material/button-toggle';
import { MatCardModule } from '@angular/material/card';
import { MatCheckboxModule } from '@angular/material/checkbox';
import { MatChipsModule } from '@angular/material/chips';
import { MatRippleModule } from '@angular/material/core';
import { MatDividerModule } from '@angular/material/divider';
import { MatExpansionModule } from '@angular/material/expansion';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatIconModule } from '@angular/material/icon';
import { MatInputModule } from '@angular/material/input';
import { MatListModule } from '@angular/material/list';
import { MatMenuModule } from '@angular/material/menu';
import { MatPaginatorModule } from '@angular/material/paginator';
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
import { MatSelectModule } from '@angular/material/select';
import { MatSidenavModule } from '@angular/material/sidenav';
import { MatSnackBarModule } from '@angular/material/snack-bar';
import { MatSortModule } from '@angular/material/sort';
import { MatTableModule } from '@angular/material/table';
import { MatTabsModule } from '@angular/material/tabs';
import { MatToolbarModule } from '@angular/material/toolbar';
import { MatTreeModule } from '@angular/material/tree';
const materialModules = [
CdkTreeModule,
MatAutocompleteModule,
MatButtonModule,
MatCardModule,
MatCheckboxModule,
MatChipsModule,
MatDividerModule,
MatExpansionModule,
MatIconModule,
MatInputModule,
MatListModule,
MatMenuModule,
MatProgressSpinnerModule,
MatPaginatorModule,
MatRippleModule,
MatSelectModule,
MatSidenavModule,
MatSnackBarModule,
MatSortModule,
MatTableModule,
MatTabsModule,
MatToolbarModule,
MatFormFieldModule,
MatButtonToggleModule,
MatTreeModule,
OverlayModule,
PortalModule
];
@NgModule({
imports: [
...materialModules
],
exports: [
...materialModules
],
})
export class MaterialModule {
}
Secondary Entrypoints
Why
With Angular Libraries you get single entrypoints.
Even a single module or component import will add huge chunk to bundle
How
Secondary Entrypoints adds only what is imported
To configure secondary entrypoints add ng-package.json to folder
nx g library-secondary-entrypoint <sec-name>
Use Standalone Component
@Component({
selector: 'app-product-signal',
templateUrl: './product-signal.component.html',
styleUrls: ['./product-signal.component.scss'],
standalone: true,
imports: [JsonPipe, CommonModule],
})
export class ProductSignalComponent
implements OnInit {
}
ng generate @angular/core:standalone
Migration to Standalone
Always Check What's in your bundle
How
Use source-map-explorer
ng add @ngx-builders/analyze
ng run project-name:analyze
Always use budgets
"budgets": [
{
"type": "initial",
"maximumWarning": "100kb",
"maximumError": "150kb"
},
{
"type": "anyComponentStyle",
"maximumWarning": "6kb",
"maximumError": "10kb"
}
]
Types of budgets
bundle - The size of a specific bundle.
initial - The initial size of the app.
allScript - The size of all scripts.
all - The size of the entire app.
Types of budgets
anyComponentStyle - This size of any one component stylesheet.
anyScript - The size of any one script.
any - The size of any file.
State Management
Available Solutions
Always use es modules for lodash or moments
Avoid using commonjs modules.
Angular 10+ will give warnings if commonjs module is used
use allowedCommonJsDependencies to disable warning
Tree shakable
Image Optimization
@Component({
standalone: true
imports: [NgOptimizedImage],
})
class MyStandaloneComponent {}
providers: [
provideImgixLoader("https://abc.com/"),
],
<img ngSrc="logo.png" width="200" height="100">
Use Strict Mode
ng generate application [project-name] --strict
use CDN to serve the assets
Low network latency
High availability and better analytics
Decrease server load
Virtual Scroll
Available Solutions
References
https://indepth.dev/are-you-using-scss-properly/
https://indepth.dev/stop-using-shared-material-module/
twitter.com/SantoshYadavDev
github.com/SantoshYadavDev
https://www.linkedin.com/in/SantoshYadavDev/
santoshyadav.dev
Thank you