Skip to content

Commit

Permalink
feat(lib): lazy url config
Browse files Browse the repository at this point in the history
  • Loading branch information
ChristopherPHolder committed Oct 13, 2024
1 parent c8de395 commit 16c6206
Show file tree
Hide file tree
Showing 7 changed files with 66 additions and 41 deletions.
8 changes: 4 additions & 4 deletions packages/ngx-fast-icon-demo/src/app/app.component.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { Component, inject, PLATFORM_ID } from '@angular/core';
import { ActivatedRoute, NavigationEnd, Router, RouterOutlet } from '@angular/router';
import { NavigationEnd, Router, RouterOutlet } from '@angular/router';

import { filter, map, Observable, startWith } from 'rxjs';
import {MediaMatcher} from '@angular/cdk/layout';
import {ShellComponent} from './misc/shell.component';
import {AsyncPipe, isPlatformServer} from '@angular/common';
import { MediaMatcher } from '@angular/cdk/layout';
import { ShellComponent } from './misc/shell.component';
import { AsyncPipe, isPlatformServer } from '@angular/common';

@Component({
selector: 'ngx-fast-icon-root',
Expand Down
16 changes: 8 additions & 8 deletions packages/ngx-fast-icon-demo/src/app/app.config.server.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
import { join } from 'node:path';
import { readFileSync } from 'node:fs';
import { readFile } from 'node:fs/promises';
import { cwd } from 'node:process';

import { ApplicationConfig, Injectable, mergeApplicationConfig } from '@angular/core';
import { provideServerRendering } from '@angular/platform-server';

import { Observable, of } from 'rxjs';
import { from, Observable, of, switchMap } from 'rxjs';

import { provideFastSVG, SvgLoadStrategy } from '@push-based/ngx-fast-svg';

import { appConfig } from './app.config';

@Injectable()
export class SvgLoadStrategySsr extends SvgLoadStrategy {
load(url: string): Observable<string> {
const iconPath = join(process.cwd(), 'packages', 'ngx-fast-icon-demo', 'src', url);
const iconSVG = readFileSync(iconPath, 'utf8')
return of(iconSVG);
export class SvgLoadStrategySsr implements SvgLoadStrategy {
config = (url: string) => of(join(cwd(), 'packages', 'ngx-fast-icon-demo', 'src', 'assets', 'svg-icons', url));
load(iconPath$: Observable<string>) {
return iconPath$.pipe(switchMap((iconPath) => from(readFile(iconPath, { encoding: 'utf8' }))))
}
}

Expand All @@ -24,7 +24,7 @@ const serverConfig: ApplicationConfig = {
provideServerRendering(),
provideFastSVG({
svgLoadStrategy: SvgLoadStrategySsr,
url: (name: string) => `assets/svg-icons/${name}.svg`,
url: (name: string) => `${name}.svg`,
}),
],
};
Expand Down
14 changes: 2 additions & 12 deletions packages/ngx-fast-icon-demo/src/app/app.config.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ApplicationConfig, Injectable } from '@angular/core';
import { ApplicationConfig } from '@angular/core';
import {
provideRouter,
withComponentInputBinding,
Expand All @@ -9,20 +9,11 @@ import { provideHttpClient, withFetch } from '@angular/common/http';
import { provideClientHydration } from '@angular/platform-browser';
import { provideAnimations } from '@angular/platform-browser/animations';

import { provideFastSVG, SvgLoadStrategyImpl } from '@push-based/ngx-fast-svg';
import { provideFastSVG } from '@push-based/ngx-fast-svg';
import { provideAngularSvgIcon } from 'angular-svg-icon';
import { provideIonicAngular } from '@ionic/angular/standalone';

import { appRoutes } from './app.routes';
import { Observable, of, switchMap, timer } from 'rxjs';

@Injectable({ providedIn: 'root' })
export class ConfigService extends SvgLoadStrategyImpl {
lazy$ = timer(10_000)
override config(url: string): Observable<string> {
return this.lazy$.pipe(switchMap(() => of(url)))
}
}

export const appConfig: ApplicationConfig = {
providers: [
Expand All @@ -42,7 +33,6 @@ export const appConfig: ApplicationConfig = {
provideIonicAngular({}),
provideFastSVG({
url: (name: string) => `assets/svg-icons/${name}.svg`,
svgLoadStrategy: ConfigService
}),
],
};
45 changes: 38 additions & 7 deletions packages/ngx-fast-lib/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,12 +102,14 @@ During setup phase you can provide additional optional settings such as:
svgLoadStrategy?: Type<SvgLoadStrategy>;
```

`svgLoadStrategy` can be any injectable class that has `load` method that accepts url and returns observable string:
`svgLoadStrategy` can be any injectable class that has `config` that excepts method that accepts url and returns observable string,
and `load` which accepts the configured url as an observable and returns the svg as an observable string.

```typescript
@Injectable()
export abstract class SvgLoadStrategy {
abstract load(url: string): Observable<string>;
abstract config(url: string): Observable<string>;
abstract load(url: Observable<string>): Observable<string>;
}
```

Expand Down Expand Up @@ -164,10 +166,9 @@ You can provide your own SSR loading strategy that can look like this:
```typescript
@Injectable()
export class SvgLoadStrategySsr implements SvgLoadStrategy {
load(url: string): Observable<string> {
const iconPath = join(process.cwd(), 'dist', 'app-name', 'browser', url);
const iconSVG = readFileSync(iconPath, 'utf8');
return of(iconSVG);
config = (url: string) => of(join(cwd(), 'path', 'to', 'svg', 'assets', url));
load(iconPath$: Observable<string>) {
return iconPath$.pipe(switchMap((iconPath) => from(readFile(iconPath, { encoding: 'utf8' }))));
}
}
```
Expand All @@ -187,14 +188,44 @@ And then just provide it in you server module.
providers: [
provideFastSVG({
svgLoadStrategy: SvgLoadStrategySsr,
url: (name: string) => `assets/svg-icons/${name}.svg`,
url: (name: string) => `${name}.svg`,
}),
],
bootstrap: [AppComponent],
})
export class AppServerModule {}
```

#### Providing a lazy configuration

If you need to provide a lazy configuration you can use the config method in the `SvgLoadStrategy`:

```typescript
@Injectable()
class LazyConfigSvgLoadStrategy extends SvgLoadStrategyImpl {
lazyConfigService = inject(SvgConfigService);
override config(url: string) {
return this.lazyConfigService.urlConfig(url);
}
}
```

And pass it to the provider function:

```typescript
import { provideFastSVG } from '@push-based/ngx-fast-svg';

bootstrapApplication(AppComponent, {
providers: [
// ... other providers
provideFastSVG({
url: (name: string): Observable<string> => inject(ConfigService).svgUrl(name),
svgLoadStrategy: LazyConfigSvgLoadStrategy,
})
]
});
```

## Features

### :sloth: Lazy loading for SVGs
Expand Down
2 changes: 1 addition & 1 deletion packages/ngx-fast-lib/src/lib/svg-registry.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ export class SvgRegistry {

// trigger fetch
this.svgLoadStrategy
.load(this.svgOptions.url(svgName))
.load(this.url(svgName))
.subscribe({
next: (body: string) => this.cacheSvgInDOM(svgId, body),
error: console.error
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
import { Observable, of } from 'rxjs';
import { Observable } from 'rxjs';
import { Injectable } from '@angular/core';

@Injectable()
export abstract class SvgLoadStrategy {
abstract load(url: string | Observable<string>): Observable<string>;
config(url: string): Observable<string> {
return of(url)
};
abstract config(url: string): Observable<string>;
abstract load(url: Observable<string>): Observable<string>;
}
14 changes: 10 additions & 4 deletions packages/ngx-fast-lib/src/lib/token/svg-load.strategy.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
import { from, Observable } from 'rxjs';
import { from, Observable, of, switchMap } from 'rxjs';
import { getZoneUnPatchedApi } from '../internal/get-zone-unpatched-api';
import { SvgLoadStrategy } from './svg-load.strategy.model';
import { Injectable } from '@angular/core';

export class SvgLoadStrategyImpl extends SvgLoadStrategy {
@Injectable()
export class SvgLoadStrategyImpl implements SvgLoadStrategy {
fetch = getZoneUnPatchedApi('fetch', window as any);

load(url: string): Observable<string> {
return from(fetch(url).then((res) => (!res.ok ? '' : res.text())));
load(url$: Observable<string>): Observable<string> {
return url$.pipe(switchMap((url) => {
return from(fetch(url).then((res) => (!res.ok ? '' : res.text())));
}));
}

config = (url: string) => of(url);
}

0 comments on commit 16c6206

Please sign in to comment.