The mysterious three tokens of Angular: APP_BOOTSTRAP_LISTENER, APP_INITIALIZER, PLATFORM_INITIALIZER
Tags: angular, tip
Published: 2022-03-05 10:26:21

If you are anything like me, chances are, you do not have a huge attention span, and you keep your memory space for more important things than to know what each of these tokens mean or how they work! So I setout to have a quick test to see which gets fired first, and what each expects. Through trial and error, and with zero regards to what goes under the hood.

Here is the [StackBlitz](https://stackblitz.com/edit/token-test?devtoolsheight=33) project.

### The documentation
Sucks! But here is what we are fishing for:

[APP_BOOTSTRAP_LISTENER](https://angular.io/api/core/APP_BOOTSTRAP_LISTENER) 
```
const APP_BOOTSTRAP_LISTENER: InjectionToken<((compRef: ComponentRef<any>) => void)[]>;

// we need to write a function that returns a function with this signature:
(compRef: ComponentRef<any>) => void

```

[APP_INITIALIZER](https://angular.io/api/core/APP_INITIALIZER)
```
const APP_INITIALIZER: InjectionToken<readonly (() => void | Observable<unknown> | Promise<unknown>)[]>;

// we need to write a function that returns a function with this signature (I choose observable):
() => Observable<any>
```

[PLATFORM_INITIALIZER](https://angular.io/api/core/PLATFORM_INITIALIZER)
```
const PLATFORM_INITIALIZER: InjectionToken<(() => void)[]>;

// we need to write a function that returns a function with this signature 
() => void
```

The first two are provided in `AppModule` and the third is mysteriously provided in `platformBrowserDynamic`, don't know why, don't care. The tip was found [buried in stackoverflow](https://stackoverflow.com/questions/55609911/platform-initializer-injector-token-in-not-working).

### Adding the tokens
Adding the tokens first, then writing the functions later, so that I don't lose my sanity. In  AppModule:
```
@NgModule({
  imports: [BrowserModule, HttpClientModule, CommonModule],
  declarations: [AppComponent],
  bootstrap: [AppComponent],
  providers: [
    {
      provide: APP_BOOTSTRAP_LISTENER,
      useFactory: bootstrapFactory, // will be created
      multi: true,
      deps: [InitService], // will be created to see if it works
    },
    {
      provide: APP_INITIALIZER,
      useFactory: initFactory, // will be created
      multi: true,
      deps: [InitService], // will be created to see if it works
    },
  ],
})
export class AppModule {}

```
In `main.ts` as an argument to `platformBrowserDynamic`
```
platformBrowserDynamic([
  {
    provide: PLATFORM_INITIALIZER,
    useValue: platformInitFactory, // will be created
    multi: true,
    deps: [InitService] // will be created to see if it works
  },
])
  .bootstrapModule(AppModule)
  .catch((err) => console.error(err));
```
### The factories
Find them in `/services/initialize.service.ts` file in stackblitz above. The factories are simple functions that return functions with matching signatures, and sweet ol' `console.log` for each step. Let's see which gets called first, and what it returns. Let me also inject a dummy service to see if it is at all usable:
```
import { Injectable } from '@angular/core';
import { Observable, of } from 'rxjs';

export const initFactory = (init: InitService): (() => Observable<any>) => {
  console.log('APP_INITIALIZER factory called', init);
  return () => {
    console.log('APP_INITIALIZER callback');
    return of(true);
  };
};

export const platformInitFactory = (a: InitService): (() => void) => {
  console.log('PLATFORM_INITIALIZER factory called', a);
  return () => {
    console.log('PLATFORM_INITIALIZER callback');
  };
};

export const bootstrapFactory = (x: InitService): ((c: ComponentRef<any>) => void) => {
  console.log('APP_BOOTSTRAP_LISTENER factory called', x);
  return (c: ComponentRef<any>) => {
    console.log('APP_BOOTSTRAP_LISTENER Callback:', c.location.nativeElement);
  };
};

@Injectable({
  providedIn: 'root',
})
export class InitService {
 // nothing yet, I want to see how I can utilize this
}
```
Running this in StackBlitz gets me the following
```
/*
PLATFORM_INITIALIZER factory called undefined
APP_INITIALIZER factory called InitService {}
APP_INITIALIZER callback
APP_BOOTSTRAP_LISTENER factory called InitService {}
APP_BOOTSTRAP_LISTENER Callback: HTMLElement...
*/
```
So, 
- PLATFORM_INITIALIZER gets called first but has no visibility for dependencies
- The PLATFORM_INITIALIZER call back function was never called! I shall unleash my wrath upon it
- APP_INITIALIZER is fired next, it has access to dependencies, and it allows an asynchronous response
- APP_BOOTSTRAP_LISTENER is garnish, accesses both dependencies and the app component, I cannot think of a use case for it.
- Angular docs of these tokens pretty much sucks--but otherwise, they are awesome, don't hate me please!

### Use cases
The most useful one is obviously `APP_INITIALIZER`, I can inject HTTP Client and load something from server upon first initialization, say, configurations?

The second use case I can think of is inject actual JS file from the `index.html` and map it internally to a `typescript` interface.

I will attempt to do both, on a different post. 👋🏼