Skip to content

Commit 37a7caf

Browse files
committed
feat: added lazy root component
1 parent b546203 commit 37a7caf

File tree

8 files changed

+275
-39
lines changed

8 files changed

+275
-39
lines changed

README.md

Lines changed: 162 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -90,22 +90,166 @@ fast(bootstrapApplication, AppComponent, {
9090
});
9191
```
9292

93-
#### Provider example
93+
### Providers
9494

95-
In the following example, we demonstrate how to define and export an array of providers that include both Provider and EnvironmentProviders. This array can be used with ngx-fastboot to dynamically load and resolve these providers during application bootstrap, optimizing the initial load performance.
95+
`ngx-fastboot` provides great flexibility in how providers are loaded. Each element of the `providers` field can be either a **single provider** or an **array of providers**, depending on the needs of your application.
9696

97+
You can specify these providers in three main ways:
98+
99+
- **Static import**: The traditional method used during the application's bootstrap, where providers are imported and directly included at configuration time. This approach is simple but can increase the initial bundle size.
100+
101+
- **Dynamic Named Import**: To reduce the bundle size, you can load providers dynamically using a named import. In this way, providers are only loaded when they are actually needed.
102+
103+
- **Dynamic Default Import**: Similar to named import, but loads the provider or a group of providers using the default export of the module. This is useful when a module exports a single provider or an array of providers as a default value.
104+
105+
#### Static Import
106+
107+
`main.ts`
108+
```typescript
109+
import { AppComponent } from './app.component';
110+
import { bootstrapApplication } from '@angular/platform-browser';
111+
import { MyProvider } from 'providers/my-provider';
112+
import { OtherProvider } from 'providers/other-provider';
113+
import { fast } from 'ngx-fastboot';
114+
115+
fast(bootstrapApplication, AppComponent, {
116+
providers: [
117+
MyProvider,
118+
OtherProvider,
119+
]
120+
}).then(appRef => {
121+
console.log('App is bootstrapped');
122+
}).catch(error => {
123+
console.error('Error bootstrapping the app', error);
124+
});
125+
```
126+
127+
#### Dynamic Named Import
128+
129+
`providers/my-provider.ts`
130+
```typescript
131+
export const MyProvider: Provider = ....;
132+
```
133+
134+
`providers/other-provider.ts`
135+
```typescript
136+
export const OtherProvider = [
137+
provideHttpClient(),
138+
ReactiveFormsModule,
139+
provideZoneChangeDetection({ eventCoalescing: true }),
140+
] satisfies Array<Provider | EnvironmentProviders>;
141+
```
142+
143+
`main.ts`
144+
```typescript
145+
import { AppComponent } from './app.component';
146+
import { bootstrapApplication } from '@angular/platform-browser';
147+
import { fast } from 'ngx-fastboot';
148+
149+
fast(bootstrapApplication, AppComponent, {
150+
providers: [
151+
() => import('providers/my-provider').then((m) => m.MyProvider), // single
152+
() => import('providers/other-provider').then((m) => m.OtherProvider), // array
153+
]
154+
}).then(appRef => {
155+
console.log('App is bootstrapped');
156+
}).catch(error => {
157+
console.error('Error bootstrapping the app', error);
158+
});
159+
```
160+
161+
#### Dynamic Default Import
162+
`providers/my-provider.ts`
97163
```typescript
98-
import { provideHttpClient } from '@angular/common/http';
99-
import { EnvironmentProviders, Provider, provideZoneChangeDetection } from '@angular/core';
100-
import { ReactiveFormsModule } from '@angular/forms';
164+
const MyProvider: Provider = ....;
165+
export default MyProvider;
166+
```
101167

168+
`providers/other-provider.ts`
169+
```typescript
102170
export default [
103171
provideHttpClient(),
104172
ReactiveFormsModule,
105173
provideZoneChangeDetection({ eventCoalescing: true }),
106174
] satisfies Array<Provider | EnvironmentProviders>;
107175
```
108176

177+
`main.ts`
178+
```typescript
179+
import { AppComponent } from './app.component';
180+
import { bootstrapApplication } from '@angular/platform-browser';
181+
import { fast } from 'ngx-fastboot';
182+
183+
fast(bootstrapApplication, AppComponent, {
184+
providers: [
185+
() => import('providers/my-provider'), // single
186+
() => import('providers/other-provider'), // array
187+
]
188+
}).then(appRef => {
189+
console.log('App is bootstrapped');
190+
}).catch(error => {
191+
console.error('Error bootstrapping the app', error);
192+
});
193+
```
194+
195+
#### Full example
196+
197+
`main.ts`
198+
```typescript
199+
import { AppComponent } from './app.component';
200+
import { bootstrapApplication } from '@angular/platform-browser';
201+
import { MyStaticImportedProvider } from './providers/my-static-imported-provider';
202+
import { fast } from 'ngx-fastboot';
203+
204+
fast(bootstrapApplication, AppComponent, {
205+
providers: [
206+
MyStaticImportedProvider,
207+
() => import('providers/my-provider').then((m) => m.MyProvider),
208+
() => import('providers/other-provider'),
209+
]
210+
}).then(appRef => {
211+
console.log('App is bootstrapped');
212+
}).catch(error => {
213+
console.error('Error bootstrapping the app', error);
214+
});
215+
```
216+
217+
### RootComponent
218+
219+
Similar to providers, you can manage the root component of the application both **statically** and **dynamically**. Dynamically loading the root component can help reduce the initial bundle size.
220+
221+
#### Static Import
222+
223+
The classic method to bootstrap the root component involves a static import:
224+
225+
```typescript
226+
fast(bootstrapApplication, AppComponent, {
227+
providers: [...]
228+
});
229+
```
230+
231+
#### Dynamic Named Import
232+
To optimize bundle size, the root component can be loaded dynamically with a named import:
233+
234+
```typescript
235+
fast(
236+
bootstrapApplication,
237+
() => import('./app-component').then((m) => m.AppComponent), {
238+
providers: [...]
239+
});
240+
```
241+
242+
#### Dynamic Default Import
243+
Alternatively, you can use a dynamic default import if the root component is exported as the default from the module:
244+
245+
```typescript
246+
fast(
247+
bootstrapApplication,
248+
() => import('./app-component'), {
249+
providers: [...]
250+
});
251+
```
252+
109253
### Sentry Integration Example
110254
This example shows how to integrate Sentry with ngx-fastboot for error monitoring and performance tracing in your Angular application.
111255

@@ -186,7 +330,7 @@ Dynamically loads the specified providers in the configuration and bootstraps an
186330
#### Parameters
187331

188332
- **`bootstrap`**: The Angular application's bootstrap function (typically `bootstrapApplication`).
189-
- **`rootComponent`**: The root component of the application, which should be of type `Type<unknown>`.
333+
- **`rootComponent`**: The root component of the application, which should be of type `FastComponent`.
190334
- **`options`**: (Optional) The application configuration, including the providers to be loaded. It should conform to the `FastApplicationConfig` type. Providers can be `Provider`, `EnvironmentProviders`, or lazy modules that return these providers.
191335

192336
#### Returns
@@ -221,6 +365,18 @@ export type LazyModule<T> = () => Promise<T | { default: T }>;
221365
export type AngularProvider = Provider | EnvironmentProviders;
222366
```
223367

368+
### `FastComponent`
369+
370+
```typescript
371+
export type FastComponent = Type<unknown> | LazyComponent;
372+
```
373+
374+
### `LazyComponent`
375+
376+
```typescript
377+
export type LazyComponent = LazyModule<Type<unknown>>;
378+
```
379+
224380
## Contributing
225381

226382
We welcome contributions! Please read our [Contributing Guide](CONTRIBUTING.md) to learn how you can help improve **ngx-fastboot**.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@
7070
"@semantic-release/github": "github:semantic-release/git",
7171
"@semantic-release/npm": "^12.0.1",
7272
"@semantic-release/release-notes-generator": "^14.0.0",
73-
"@types/jest": "^29.5.12",
73+
"@types/jest": "^29.5.13",
7474
"@typescript-eslint/eslint-plugin": "8.8.1",
7575
"@typescript-eslint/parser": "8.8.1",
7676
"commitlint": "19.5.0",

pnpm-lock.yaml

Lines changed: 23 additions & 23 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/lib/fast.ts

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
import { ApplicationConfig, ApplicationRef, Type } from '@angular/core';
1+
import { ApplicationConfig, ApplicationRef } from '@angular/core';
22
import type { bootstrapApplication } from '@angular/platform-browser';
33

4-
import { resolveProviders } from './resolve-providers';
5-
import { AngularProvider, FastApplicationConfig } from './types';
4+
import { resolveDependencies } from './resolve-dependencies';
5+
import { FastApplicationConfig, FastComponent } from './types';
66

77
/**
88
* Dynamically loads the specified providers in the configuration and bootstraps an Angular application.
@@ -12,7 +12,8 @@ import { AngularProvider, FastApplicationConfig } from './types';
1212
* be loaded asynchronously. This function handles resolving these providers and passing them to the bootstrap method.
1313
*
1414
* @param bootstrap - The Angular application's bootstrap function (typically `bootstrapApplication`).
15-
* @param rootComponent - The root component of the application, which should be of type `Type<unknown>`.
15+
* @param rootComponent - The root component of the application, which should be of type `FastComponent`
16+
* (ie. Type<unknown> or lazy module that return this component).
1617
* @param options - (Optional) The application configuration, including the providers to be loaded. It should conform
1718
* to the `FastApplicationConfig` type. Providers can be `Provider`, `EnvironmentProviders`,
1819
* or lazy modules that return these providers.
@@ -39,16 +40,17 @@ import { AngularProvider, FastApplicationConfig } from './types';
3940
*/
4041
export const fast = async (
4142
bootstrap: typeof bootstrapApplication,
42-
rootComponent: Type<unknown>,
43+
rootComponent: FastComponent,
4344
options?: FastApplicationConfig,
4445
): Promise<ApplicationRef> => {
45-
const resolvedProviders: Array<AngularProvider> = await resolveProviders(
46+
const { component, providers } = await resolveDependencies(
47+
rootComponent,
4648
options?.providers ?? [],
4749
);
4850
const nextOptions: ApplicationConfig = {
4951
...options,
50-
providers: resolvedProviders,
52+
providers,
5153
};
5254

53-
return bootstrap(rootComponent, nextOptions);
55+
return bootstrap(component, nextOptions);
5456
};

0 commit comments

Comments
 (0)