By Vincent OGLOBLINSKY & Wassim CHEGHAM
How To Be Successful With Your Next Angular Projects.
Web Architect at SII
GDE Web
ngx.tools, xlayers.dev, hexa.run
Sr. Cloud Advocate at MICROSOFT
GDE Web
Author of Compodoc
@vogloblinsky
@manekinekko
Angular Core Team
import foo from 'bar';
@NgModule({...})
export class AppModule {}
Project's internal APIs.
Interceptors, ExceptionHandler...
No business logic!
Local & global Shared APIs
Business logic.
Business logic only!
Modules, Components, Services, Pipes, Directives...
Modules, Providers, Components, Directives, Pipes, etc.
Avoid cluttering the global Shared Module. Use local shared modules.
Avoid putting Providers in the global Shared Module (Providers corruption!)
NgModules are going to be optional in the future.
export const routes: Route[] = [
{
path: '',
redirectTo: '/home',
pathMatch: 'full'
},
{
path: 'home',
loadChildren: () => import('../home/home.module')
.then(e => e.HomeModule)
},
{
path: 'editor',
loadChildren: () => import('./editor/editor.module')
.then(e => e.EditorModule)
},
{
path: 'upload',
loadChildren: () => import('./upload/upload.module')
.then(e => e.UploadModule)
},
{
path: '**',
redirectTo: '/home'
}
];
export const routes: Route[] = [
{
path: '',
redirectTo: '/home',
pathMatch: 'full'
},
{
path: 'home',
component: HomeComponent
},
{
path: 'editor',
component: EditorComponent
},
{
path: 'upload',
component: UploadComponent
},
{
path: '**',
redirectTo: '/home'
}
];
.
├── BUILD.bazel
├── app-routing.module.ts
├── app.component.html
├── app.component.ts
├── app.module.ts
├── billing
│ ├── BUILD.bazel
│ ├── billing.module.ts
│ ├── index
│ │ ├── index.component.html
│ │ ├── index.component.spec.ts
│ │ └── index.component.ts
│ ├── module0
│ │ ├── BUILD.bazel
│ │ ├── cmp0
│ │ │ ├── cmp0.component.html
│ │ │ ├── cmp0.component.scss
│ │ │ ├── cmp0.component.spec.ts
│ │ │ └── cmp0.component.ts
│ │ ├── cmp1
│ │ │ ├── cmp1.component.html
│ │ │ ├── cmp1.component.scss
│ │ │ ├── cmp1.component.spec.ts
│ │ │ └── cmp1.component.ts
│ │ └── module0.module.ts
│ └── module1
│ ├── BUILD.bazel
│ ├── cmp2
│ │ ├── cmp2.component.html
│ │ ├── cmp2.component.scss
│ │ ├── cmp2.component.spec.ts
│ │ └── cmp2.component.ts
│ ├── cmp3
│ │ ├── cmp3.component.html
│ │ ├── cmp3.component.scss
│ │ ├── cmp3.component.spec.ts
│ │ └── cmp3.component.ts
│ └── module1.module.ts
├── compute
│ ├── BUILD.bazel
│ ├── compute.module.ts
│ ├── index
│ │ ├── index.component.html
│ │ ├── index.component.spec.ts
│ │ └── index.component.ts
│ ├── module0
│ │ ├── BUILD.bazel
│ │ ├── cmp4
│ │ │ ├── cmp4.component.html
│ │ │ ├── cmp4.component.scss
│ │ │ ├── cmp4.component.spec.ts
│ │ │ └── cmp4.component.ts
│ │ ├── cmp5
│ │ │ ├── cmp5.component.html
│ │ │ ├── cmp5.component.scss
│ │ │ ├── cmp5.component.spec.ts
│ │ │ └── cmp5.component.ts
│ │ └── module0.module.ts
│ └── module1
│ ├── BUILD.bazel
│ ├── cmp6
│ │ ├── cmp6.component.html
│ │ ├── cmp6.component.scss
│ │ ├── cmp6.component.spec.ts
│ │ └── cmp6.component.ts
│ ├── cmp7
│ │ ├── cmp7.component.html
│ │ ├── cmp7.component.scss
│ │ ├── cmp7.component.spec.ts
│ │ └── cmp7.component.ts
│ └── module1.module.ts
├── datastore
│ ├── BUILD.bazel
│ ├── datastore.module.ts
│ ├── index
│ │ ├── index.component.html
│ │ ├── index.component.spec.ts
│ │ └── index.component.ts
│ ├── module0
│ │ ├── BUILD.bazel
│ │ ├── cmp8
│ │ │ ├── cmp8.component.html
│ │ │ ├── cmp8.component.scss
│ │ │ ├── cmp8.component.spec.ts
│ │ │ └── cmp8.component.ts
│ │ ├── cmp9
│ │ │ ├── cmp9.component.html
│ │ │ ├── cmp9.component.scss
│ │ │ ├── cmp9.component.spec.ts
│ │ │ └── cmp9.component.ts
│ │ └── module0.module.ts
│ └── module1
│ ├── BUILD.bazel
│ ├── cmp10
│ │ ├── cmp10.component.html
│ │ ├── cmp10.component.scss
│ │ ├── cmp10.component.spec.ts
│ │ └── cmp10.component.ts
│ ├── cmp11
│ │ ├── cmp11.component.html
│ │ ├── cmp11.component.scss
│ │ ├── cmp11.component.spec.ts
│ │ └── cmp11.component.ts
│ └── module1.module.ts
├── functions
│ ├── BUILD.bazel
│ ├── functions.module.ts
│ ├── index
│ │ ├── index.component.html
│ │ ├── index.component.spec.ts
│ │ └── index.component.ts
│ ├── module0
│ │ ├── BUILD.bazel
│ │ ├── cmp12
│ │ │ ├── cmp12.component.html
│ │ │ ├── cmp12.component.scss
│ │ │ ├── cmp12.component.spec.ts
│ │ │ └── cmp12.component.ts
│ │ ├── cmp13
│ │ │ ├── cmp13.component.html
│ │ │ ├── cmp13.component.scss
│ │ │ ├── cmp13.component.spec.ts
│ │ │ └── cmp13.component.ts
│ │ └── module0.module.ts
│ └── module1
│ ├── BUILD.bazel
│ ├── cmp14
│ │ ├── cmp14.component.html
│ │ ├── cmp14.component.scss
│ │ ├── cmp14.component.spec.ts
│ │ └── cmp14.component.ts
│ ├── cmp15
│ │ ├── cmp15.component.html
│ │ ├── cmp15.component.scss
│ │ ├── cmp15.component.spec.ts
│ │ └── cmp15.component.ts
│ └── module1.module.ts
├── hello-world
│ ├── BUILD.bazel
│ ├── hello-world.component.html
│ ├── hello-world.component.scss
│ ├── hello-world.component.spec.ts
│ ├── hello-world.component.ts
│ └── hello-world.module.ts
├── home
│ ├── BUILD.bazel
│ ├── home.html
│ └── home.ts
├── logging
│ ├── BUILD.bazel
│ ├── index
│ │ ├── index.component.html
│ │ ├── index.component.spec.ts
│ │ └── index.component.ts
│ ├── logging.module.ts
│ ├── module0
│ │ ├── BUILD.bazel
│ │ ├── cmp16
│ │ │ ├── cmp16.component.html
│ │ │ ├── cmp16.component.scss
│ │ │ ├── cmp16.component.spec.ts
│ │ │ └── cmp16.component.ts
│ │ ├── cmp17
│ │ │ ├── cmp17.component.html
│ │ │ ├── cmp17.component.scss
│ │ │ ├── cmp17.component.spec.ts
│ │ │ └── cmp17.component.ts
│ │ └── module0.module.ts
│ └── module1
│ ├── BUILD.bazel
│ ├── cmp18
│ │ ├── cmp18.component.html
│ │ ├── cmp18.component.scss
│ │ ├── cmp18.component.spec.ts
│ │ └── cmp18.component.ts
│ ├── cmp19
│ │ ├── cmp19.component.html
│ │ ├── cmp19.component.scss
│ │ ├── cmp19.component.spec.ts
│ │ └── cmp19.component.ts
│ └── module1.module.ts
├── monitoring
│ ├── BUILD.bazel
│ ├── index
│ │ ├── index.component.html
│ │ ├── index.component.spec.ts
│ │ └── index.component.ts
│ ├── module0
│ │ ├── BUILD.bazel
│ │ ├── cmp20
│ │ │ ├── cmp20.component.html
│ │ │ ├── cmp20.component.scss
│ │ │ ├── cmp20.component.spec.ts
│ │ │ └── cmp20.component.ts
│ │ ├── cmp21
│ │ │ ├── cmp21.component.html
│ │ │ ├── cmp21.component.scss
│ │ │ ├── cmp21.component.spec.ts
│ │ │ └── cmp21.component.ts
│ │ └── module0.module.ts
│ ├── module1
│ │ ├── BUILD.bazel
│ │ ├── cmp22
│ │ │ ├── cmp22.component.html
│ │ │ ├── cmp22.component.scss
│ │ │ ├── cmp22.component.spec.ts
│ │ │ └── cmp22.component.ts
│ │ ├── cmp23
│ │ │ ├── cmp23.component.html
│ │ │ ├── cmp23.component.scss
│ │ │ ├── cmp23.component.spec.ts
│ │ │ └── cmp23.component.ts
│ │ └── module1.module.ts
│ └── monitoring.module.ts
├── networking
│ ├── BUILD.bazel
│ ├── index
│ │ ├── index.component.html
│ │ ├── index.component.spec.ts
│ │ └── index.component.ts
│ ├── module0
│ │ ├── BUILD.bazel
│ │ ├── cmp24
│ │ │ ├── cmp24.component.html
│ │ │ ├── cmp24.component.scss
│ │ │ ├── cmp24.component.spec.ts
│ │ │ └── cmp24.component.ts
│ │ ├── cmp25
│ │ │ ├── cmp25.component.html
│ │ │ ├── cmp25.component.scss
│ │ │ ├── cmp25.component.spec.ts
│ │ │ └── cmp25.component.ts
│ │ └── module0.module.ts
│ ├── module1
│ │ ├── BUILD.bazel
│ │ ├── cmp26
│ │ │ ├── cmp26.component.html
│ │ │ ├── cmp26.component.scss
│ │ │ ├── cmp26.component.spec.ts
│ │ │ └── cmp26.component.ts
│ │ ├── cmp27
│ │ │ ├── cmp27.component.html
│ │ │ ├── cmp27.component.scss
│ │ │ ├── cmp27.component.spec.ts
│ │ │ └── cmp27.component.ts
│ │ └── module1.module.ts
│ └── networking.module.ts
├── registry
│ ├── BUILD.bazel
│ ├── index
│ │ ├── index.component.html
│ │ ├── index.component.spec.ts
│ │ └── index.component.ts
│ ├── module0
│ │ ├── BUILD.bazel
│ │ ├── cmp28
│ │ │ ├── cmp28.component.html
│ │ │ ├── cmp28.component.scss
│ │ │ ├── cmp28.component.spec.ts
│ │ │ └── cmp28.component.ts
│ │ ├── cmp29
│ │ │ ├── cmp29.component.html
│ │ │ ├── cmp29.component.scss
│ │ │ ├── cmp29.component.spec.ts
│ │ │ └── cmp29.component.ts
│ │ └── module0.module.ts
│ ├── module1
│ │ ├── BUILD.bazel
│ │ ├── cmp30
│ │ │ ├── cmp30.component.html
│ │ │ ├── cmp30.component.scss
│ │ │ ├── cmp30.component.spec.ts
│ │ │ └── cmp30.component.ts
│ │ ├── cmp31
│ │ │ ├── cmp31.component.html
│ │ │ ├── cmp31.component.scss
│ │ │ ├── cmp31.component.spec.ts
│ │ │ └── cmp31.component.ts
│ │ └── module1.module.ts
│ └── registry.module.ts
├── storage
│ ├── BUILD.bazel
│ ├── index
│ │ ├── index.component.html
│ │ ├── index.component.spec.ts
│ │ └── index.component.ts
│ ├── module0
│ │ ├── BUILD.bazel
│ │ ├── cmp32
│ │ │ ├── cmp32.component.html
│ │ │ ├── cmp32.component.scss
│ │ │ ├── cmp32.component.spec.ts
│ │ │ └── cmp32.component.ts
│ │ ├── cmp33
│ │ │ ├── cmp33.component.html
│ │ │ ├── cmp33.component.scss
│ │ │ ├── cmp33.component.spec.ts
│ │ │ └── cmp33.component.ts
│ │ └── module0.module.ts
│ ├── module1
│ │ ├── BUILD.bazel
│ │ ├── cmp34
│ │ │ ├── cmp34.component.html
│ │ │ ├── cmp34.component.scss
│ │ │ ├── cmp34.component.spec.ts
│ │ │ └── cmp34.component.ts
│ │ ├── cmp35
│ │ │ ├── cmp35.component.html
│ │ │ ├── cmp35.component.scss
│ │ │ ├── cmp35.component.spec.ts
│ │ │ └── cmp35.component.ts
│ │ └── module1.module.ts
│ └── storage.module.ts
├── support
│ ├── BUILD.bazel
│ ├── index
│ │ ├── index.component.html
│ │ ├── index.component.spec.ts
│ │ └── index.component.ts
│ ├── module0
│ │ ├── BUILD.bazel
│ │ ├── cmp36
│ │ │ ├── cmp36.component.html
│ │ │ ├── cmp36.component.scss
│ │ │ ├── cmp36.component.spec.ts
│ │ │ └── cmp36.component.ts
│ │ ├── cmp37
│ │ │ ├── cmp37.component.html
│ │ │ ├── cmp37.component.scss
│ │ │ ├── cmp37.component.spec.ts
│ │ │ └── cmp37.component.ts
│ │ └── module0.module.ts
│ ├── module1
│ │ ├── BUILD.bazel
│ │ ├── cmp38
│ │ │ ├── cmp38.component.html
│ │ │ ├── cmp38.component.scss
│ │ │ ├── cmp38.component.spec.ts
│ │ │ └── cmp38.component.ts
│ │ ├── cmp39
│ │ │ ├── cmp39.component.html
│ │ │ ├── cmp39.component.scss
│ │ │ ├── cmp39.component.spec.ts
│ │ │ └── cmp39.component.ts
│ │ └── module1.module.ts
│ └── support.module.ts
└── todos
├── BUILD.bazel
├── reducers
│ ├── BUILD.bazel
│ └── reducers.ts
├── todos.component.html
├── todos.component.scss
├── todos.component.ts
└── todos.module.ts
84 directories, 271 files
$ ng generate library my-awesome-logger
➜ scripts git:(master) / tree
.
├── clean-changelog.js
├── cloudbuild
│ ├── deploy.sh
│ ├── kubectl
│ │ ├── Dockerfile
│ │ ├── cloudbuild.yaml
│ │ ├── kubectl.bash
│ │ └── publish.sh
│ ├── ngcontainer
│ │ ├── Dockerfile
│ │ ├── cloudbuild.yaml
│ │ ├── nginx.conf
│ │ └── publish.sh
│ └── xlayers.template.yaml
├── github-create-comment.bash
├── local-build.sh
└── stamp-build.bash
$ ng add @company/deploy
import { ApiService } from '../../../core/api.service.ts';
import { CatsService } from '../../../services/cats.service.ts';
// tsconfig.json
{
"CompilerOptions": {
"baseUrl": "src",
"paths": {
"@core/*": ["app/core/*"]
"@services/*": ["app/services/*"]
}
}
}
import { ApiService } from '@core/api.service.ts';
import { CatsService } from '@services/cats.service.ts';
You should start investing in Schematics and Builders.
Components
Code Generation
Compiler *
(Parser, Lexer, AST)
VM Code
(Renderer *)
JIT Compilation
(run time)
AOT Compilation (build time)
* In v8: ViewEngine. In v9+: Ivy
Build in Prod mode (AOT) as often as possible.
Architect.ScheduleTarget()
ng build --prod
angular.json: defaultProject
angular.json: architect.build.builder
(e.g. @angular-devkit/build-angular:browser)
Create a Webpack plugin:
Common, Browser, Stats, Styles, Worker, Analytics, AOT or JIT.
browserBuild()
AOT && buildOptimizerLoader()
Architect.run()
new AngularCompilerPlugin() (@ngtools/webpack)
ngc (ViewEngine)
ngcc (Ivy)
Consider keeping up to date with the latest releases:
ng update [--next]
You should start investing in Bazel (demo!).
$ npm i webpack-bundle-analyzer -D
$ ng build --stats-json
$ webpack-bundle-analyzer dist/MyBundle/stats.json
Setup a bundles analyzer as part of your CI/CD.
You should consider the Component DevKit.
Avoid importing Fat Shared Modules in the TestBed Module!
this.entries$ = this.queries$.pipe(
map((query: string) => query ? query.trim() : ''),
filter(Boolean),
debounceTime(500),
distinctUntilChanged(),
switchMap((query: string) => this.fetchEntries(query)),
filterByOwnerType(OwnerType.User)
);
this.organizations$ = this.selectedRepository$.pipe(
map((repository) => repository && repository.owner.organizations_url),
switchMap((url: string | false) => {
return url ? this.fetchUserOrganizations(url) : of(undefined);
}),
);
Embrace Reactive Functional Programming.
Don't let one person HOLDS all the knowledge.
00. Avoid cluttering the global Shared Module. Use local shared modules.
02. NgModules are going to be optional in the future.
01. Avoid putting Providers in the global Shared Module.
03. You should start investing in Schematics and Builders.
04. Build in Prod mode as often as possible.
05. Consider keeping up to date with the latest releases.
06. You should start investing in Bazel.
07. Setup the bundles analyzer as part of your CI/CD.
08. You should consider the Component DevKit.
10. Embrace Reactive Functional Programming.
11. Don't let one person HOLDS all the knowledge.
09. Avoid importing Fat Shared Modules in the TestBed Module!