# Ways to bootstrap an application
## Approach 1 (Abandoned)
### main.ts
```ts
import { bootstrapApplication } from '@angular/platform-browser';
import { AppRoot } from './app';
import { providers } from './config';
const bootstrap = () =>
bootstrapApplication(AppRoot, { providers }));
if (document.readyState === 'complete') {
await bootstrap().catch(err => console.error(err);
} else {
document.addEventListener('DOMContentLoaded',
() => bootstrap().catch(err => console.error(err));
}
```
### main-server.ts
```ts!
import { bootstrapApplication } from '@angular/platform-browser'; // It's akward that the server depends on the browser module
import { AppRoot } from './app';
import { providers } from './config';
export default bootstrapApplication(AppRoot, {
providers: [
...providers,
provideServerModule(),
provideRouter(ROUTES),
...
],
});
```
## Approach 2 (Abandoned)
### main.ts
```ts
import { bootstrapApplication } from '@angular/platform-browser';
import { AppRoot } from './app';
import { config } from './config';
const bootstrap = (extraConfig: ApplicationConfig) =>
bootstrapApplication(AppRoot, deepMerge(config, extraConfig)));
if (document.readyState === 'complete') {
await bootstrap().catch(err => console.error(err);
} else {
document.addEventListener('DOMContentLoaded',
() => bootstrap().catch(err => console.error(err));
}
export default bootstrap;
```
### main-server.ts
```ts
import { provideServerModule } from '@angular/platform-server';
import bootstrap from './main';
export default bootstrap({
providers: [
provideServerModule(),
provideRouter(ROUTES),
]
});
```
## Approach 3 (Abandoned)
### main.ts
```ts
import { bootstrapApplication } from '@angular/platform-browser';
import { AppRoot } from './app';
import { config } from './config';
const bootstrap = (appConfig: ApplicationConfig = config) =>
bootstrapApplication(AppRoot, appConfig);
if (document.readyState === 'complete') {
await bootstrap().catch(err => console.error(err));
} else {
document.addEventListener('DOMContentLoaded',
() => bootstrap().catch(err => console.error(err)));
}
export default bootstrap;
```
### main-server.ts
```ts
import { provideServerModule } from '@angular/platform-server';
import { config } from './config';
import bootstrapApp from './main';
const bootstrap = (extraConfig: ApplicationConfig) =>
bootstrapApp(
AppRoot,
deepMerge(
config,
{
providers: [
provideServerModule(),
provideRouter(ROUTES),
],
},
extraConfig,
),
);
export default bootstrap;
```
## Approach 4 (Abandoned)
`bootstrapApplication` code is generated internally in the CLI for both the client and server bundles. This is something that came too mind that I wanted to share. I personally do not think I'd go for this as it can feel too magical and might be harder to debug bootstrapping issues.
### main.ts
```ts
import { AppRoot } from './app';
import { config } from './config';
const bootstrapAppConfig = {
component: AppRoot,
applicationConfig: config,
};
export default bootstrapAppConfig;
```
### main-server.ts
```ts
import browserConfig from './main';
const serverConfig = {
providers: [
provideServerModule(),
provideRouter(ROUTES),
],
};
const bootstrapAppConfig = [browserConfig, serverConfig];
export default bootstrapAppConfig;
```
## New Approches Intro
Potentially by default we might not even need to create the main-server file.
Given that:
* `provideServerModule` is added as a platform provider when rendering SSR/SSG. Maybe though this would cause more complexity for users when trying to figure out how to add a provider for server?
* `withServerTransition` becomes redundant following https://github.com/angular/angular/pull/48253
* Handle app-shell completly differently. Currently app-shell is just another root on the server. Following some explorations I feel that we can just avoid adding additional routes instead just bootstrap the application using `AppShell` instead of `AppRoot` as component. This comes with a drawback of 1 extra file, but removed the need of having server specific routing.
## Approach 5 (New)
### main.ts
```ts
import { Providers } from '@angular/core';
import { bootstrapApplication } from '@angular/platform-browser';
import { AppRoot } from './app';
import { config } from './config';
const bootstrap = (extraProviders: Providers[]|undefined, rootComponent = AppRoot) =>
bootstrapApplication(rootComponent, {
...config,
providers: [
...config.providers
...extraProviders,
]
});
// Should `bootstrap()` be done by the CLI or not?
// await bootstrap();
export default bootstrap;
```
### main-server.ts
```ts
import { Providers } from "@angular/core";
import { provideServerModule } from "@angular/platform-server";
import bootstrapApp from "./main";
const bootstrap = (extraProviders: Providers[] = []) =>
bootstrapApp([
provideServerModule(),
...extraProviders,
]);
export default bootstrap;
```
### app-shell.ts
```ts
import { Providers } from "@angular/core";
import { provideServerModule } from "@angular/platform-server";
import bootstrapApp from "./main";
const bootstrap = (extraProviders: Providers[] = []) =>
bootstrapApp([
provideServerModule(),
...extraProviders,
], AppShell);
export default bootstrap;
```
## Approach 6 (New)
Maybe we are trying to over thinking it and the simplest would to use `bootstrapApplication` directly.
### browser.ts
```ts
import { bootstrapApplication } from '@angular/platform-browser';
import { AppRoot } from './app';
import { config } from './config';
const bootstrap = () => bootstrapApplication(AppRoot, config);
// Should `bootstrap()` be done by the CLI or not?
// await bootstrap();
export default bootstrap;
```
### server.ts
```ts
// This is a bit odd that server depends on platform-browser
// Maybe @angular/platform-server could have a bootstrapApplication that already provides the `ServerModule`?
import { bootstrapApplication } from '@angular/platform-browser';
import { AppRoot } from './app';
import { config } from './config';
const bootstrap = () => bootstrapApplication(AppRoot, {
...config,
providers: [
...config.providers,
provideServerModule(),
]
});
export default bootstrap;
```
### app-shell.ts
```ts
import { bootstrapApplication } from '@angular/platform-browser';
import { AppShell } from './app-shell';
import { config } from './config';
const bootstrap = () => bootstrapApplication(AppShell, {
...config,
providers: [
...config.providers,
provideServerModule(),
]
});
export default bootstrap;
```
## Approach 7 (New)
### main.ts
```ts!
import { bootstrapApplication } from '@angular/platform-browser';
import { App } from './app';
import CONFIG from './app.config';
const bootstrap = () => bootstrapApplication(App, CONFIG);
export default bootstrap;
```
### main.server.ts
```ts!
import { mergeConfig } from '@angular/platform-browser';
import { bootstrapApplication } from '@angular/platform-server';
import { App } from './app';
import CONFIG from './app.config';
// By default we don't need to add overrides.
// This is because bootstrapApplication provides the ServerModule.
// We might not even need to provide a mergeConfig in this case.
const SERVER_CONFIG = {};
const bootstrap = () =>
bootstrapApplication(App, mergeConfig(SERVER_CONFIG, CONFIG));
export default bootstrap;
```
When using an app-shell the `SERVER_CONFIG` will be updated to:
```ts!
// For the app-shell use-case we just add an additional route.
// This is the same as `providerRoute([{ ... }])` which is deprecated.
const SERVER_CONFIG = {
providers: [{
provide: ROUTES,
multi: true,
useValue: [
{
path: 'shell',
component: AppShellComponent
},
],
}],
};
```
## Questions
* Do we need to expose a way for users to override/set `platformProviders`? My 2 cents is no.
* What are the cases that we need different routes on client and server? Currently there is only one case which is for the app-shell.
* Should we internally call `renderApplication` from the exported `bootstrapApplication`?
* Can we add additional providers after bootstrapping but before rendering such as `ɵSERVER_CONTEXT`, `INITIAL_CONFIG` etc? (If not probably Approach 3 would be needed to provide providers from the CLI/Universal
* Benefits of app-shell as a route vs bootstrapped component.