Skip to content

Commit fd4c892

Browse files
authored
perf: reduce routing module bundle size (#172)
1 parent c314cc2 commit fd4c892

7 files changed

+61
-143
lines changed
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import { MockProvider, MockService } from 'ng-mocks'
2+
import { ActivatedRouteSnapshot } from '@angular/router'
3+
import { TestBed } from '@angular/core/testing'
4+
import {
5+
CurrentRouteDataMetadataStrategy,
6+
ROUTING_KEY,
7+
} from './current-route-data-metadata-strategy'
8+
import { MetadataService } from '../../core'
9+
10+
describe('Current route data metadata strategy', () => {
11+
describe('resolve', () => {
12+
it('returns current route snapshot (last child)', () => {
13+
const dummyRouteMetadata = { title: 'dummy' }
14+
const rootSnapshot = MockService(ActivatedRouteSnapshot, {
15+
firstChild: {
16+
firstChild: {
17+
firstChild: MockService(ActivatedRouteSnapshot, {
18+
data: { [ROUTING_KEY]: dummyRouteMetadata },
19+
}),
20+
},
21+
},
22+
} as Partial<ActivatedRouteSnapshot>)
23+
const sut = makeSut()
24+
25+
expect(sut.resolve(rootSnapshot)).toEqual(dummyRouteMetadata)
26+
})
27+
})
28+
})
29+
30+
function makeSut() {
31+
TestBed.configureTestingModule({
32+
providers: [
33+
CurrentRouteDataMetadataStrategy,
34+
MockProvider(MetadataService),
35+
],
36+
})
37+
return TestBed.inject(CurrentRouteDataMetadataStrategy)
38+
}
Lines changed: 9 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,26 @@
11
import { ActivatedRouteSnapshot } from '@angular/router'
2-
import { Inject, Injectable } from '@angular/core'
3-
import {
4-
GET_CURRENT_SNAPSHOT_FROM_ROOT_SNAPSHOT_TOKEN,
5-
GetCurrentSnapshotFromRootSnapshot,
6-
} from './get-current-snapshot-from-root-snapshot'
2+
import { Injectable } from '@angular/core'
73
import { MetadataRouteStrategy } from './metadata-route-strategy'
84
import { MetadataService, MetadataValues } from '@davidlj95/ngx-meta/core'
95
import { MetadataRouteData } from './metadata-route-data'
106

117
@Injectable({ providedIn: 'root' })
12-
export class CurrentRouteDataMetadataStrategy
13-
implements MetadataRouteStrategy<MetadataValues>
14-
{
15-
constructor(
16-
@Inject(GET_CURRENT_SNAPSHOT_FROM_ROOT_SNAPSHOT_TOKEN)
17-
private readonly getCurrentSnapshotFromRootSnapshot: GetCurrentSnapshotFromRootSnapshot,
18-
private readonly metadataService: MetadataService,
19-
) {}
8+
export class CurrentRouteDataMetadataStrategy implements MetadataRouteStrategy {
9+
constructor(private readonly metadataService: MetadataService) {}
2010

2111
resolve<T extends object>(
2212
routeSnapshot: ActivatedRouteSnapshot,
2313
): T | undefined {
24-
const currentRoute = this.getCurrentSnapshotFromRootSnapshot(routeSnapshot)
25-
return currentRoute.data[ROUTING_KEY]
14+
let currentRouteSnapshot: ActivatedRouteSnapshot = routeSnapshot
15+
while (currentRouteSnapshot.firstChild != null) {
16+
currentRouteSnapshot = currentRouteSnapshot.firstChild
17+
}
18+
return currentRouteSnapshot.data[ROUTING_KEY]
2619
}
2720

2821
set(metadata: MetadataValues | undefined): void {
2922
this.metadataService.set(metadata)
3023
}
3124
}
3225

33-
const ROUTING_KEY: keyof MetadataRouteData = 'meta'
26+
export const ROUTING_KEY: keyof MetadataRouteData = 'meta'

projects/ngx-meta/src/routing/src/get-current-snapshot-from-root-snapshot.spec.ts

Lines changed: 0 additions & 18 deletions
This file was deleted.

projects/ngx-meta/src/routing/src/get-current-snapshot-from-root-snapshot.ts

Lines changed: 0 additions & 23 deletions
This file was deleted.
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { GlobalMetadata, MetadataValues } from '@davidlj95/ngx-meta/core'
22

33
export interface MetadataRouteData {
4-
meta: GlobalMetadata | MetadataValues
4+
meta: GlobalMetadata & MetadataValues
55
}

projects/ngx-meta/src/routing/src/router-listener.service.spec.ts

Lines changed: 5 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,6 @@ describe('RouterListenerService', () => {
3131

3232
expect(events$.observed).toBeFalse()
3333
})
34-
35-
it('should report is not listening', () => {
36-
const sut = makeSut()
37-
38-
expect(sut.isListening).toBeFalse()
39-
})
4034
})
4135

4236
describe('when already listening', () => {
@@ -47,22 +41,18 @@ describe('RouterListenerService', () => {
4741
sut.listen()
4842
})
4943

50-
it('should report is listening', () => {
51-
expect(sut.isListening).toBeTrue()
52-
})
53-
5444
describe('when listening again', () => {
5545
let existingSubscription: Subscription
5646

5747
beforeEach(() => {
58-
existingSubscription = sut['subscription']!
48+
existingSubscription = sut['sub']!
5949
expect(existingSubscription).toBeDefined()
6050
spyOn(console, 'warn').and.stub()
6151
sut.listen()
6252
})
6353

6454
it('should not subscribe again', () => {
65-
expect(sut['subscription']).toBe(existingSubscription)
55+
expect(sut['sub']).toBe(existingSubscription)
6656
})
6757

6858
it('should warn about it', () => {
@@ -92,22 +82,19 @@ describe('RouterListenerService', () => {
9282
it('should log it to console', () => {
9383
const consoleWarn = spyOn(console, 'warn')
9484
const events$ = new EventEmitter()
95-
const sut = makeSut({
96-
events$,
97-
strategies: [],
98-
})
85+
const sut = makeSut({ events$ })
9986

10087
sut.listen()
10188

10289
events$.emit(makeNavigationEvent(EventType.NavigationEnd))
10390

10491
expect(consoleWarn).toHaveBeenCalledOnceWith(
105-
jasmine.stringContaining('strategies'),
92+
jasmine.stringContaining('strategy'),
10693
)
10794
})
10895
})
10996

110-
describe('when a single strategy is found', () => {
97+
describe('when a strategy is provided', () => {
11198
it('should call strategy resolve and set', () => {
11299
const metadata = { key: 'value' }
113100
const strategy = makeStrategy('single', metadata)
@@ -129,40 +116,12 @@ describe('RouterListenerService', () => {
129116
expect(strategy.set).toHaveBeenCalledOnceWith(metadata)
130117
})
131118
})
132-
133-
it('should call all strategies resolve and set in order', () => {
134-
const events$ = new EventEmitter()
135-
const strategyOneData = { key: 'one' }
136-
const strategyOne = makeStrategy('one', strategyOneData)
137-
const strategyTwoData = { key: 'two' }
138-
const strategyTwo = makeStrategy('two', strategyTwoData)
139-
const activatedRoute = MockService(ActivatedRoute)
140-
const sut = makeSut({
141-
events$,
142-
strategies: [strategyOne, strategyTwo],
143-
activatedRoute,
144-
})
145-
sut.listen()
146-
147-
events$.emit(makeNavigationEvent(EventType.NavigationEnd))
148-
149-
expect(strategyOne.resolve).toHaveBeenCalledOnceWith(
150-
activatedRoute.snapshot,
151-
)
152-
expect(strategyOne.set).toHaveBeenCalledOnceWith(strategyOneData)
153-
expect(strategyTwo.resolve).toHaveBeenCalledOnceWith(
154-
activatedRoute.snapshot,
155-
)
156-
expect(strategyTwo.set).toHaveBeenCalledOnceWith(strategyTwoData)
157-
expect(strategyOne.set).toHaveBeenCalledBefore(strategyTwo.set)
158-
})
159119
})
160120
})
161121

162122
function makeSut(
163123
opts: {
164124
events$?: EventEmitter<NavigationEvent>
165-
strategies?: ReadonlyArray<MetadataRouteStrategy>
166125
strategy?: MetadataRouteStrategy
167126
activatedRoute?: ActivatedRoute
168127
} = {},
@@ -180,31 +139,11 @@ function makeSut(
180139
MockProvider(ActivatedRoute, activatedRoute, 'useValue'),
181140
]
182141

183-
if (opts.strategies) {
184-
// multiple providers (or none if empty array)
185-
for (const strategy of opts.strategies) {
186-
providers.push(
187-
MockProvider(MetadataRouteStrategy, strategy, 'useValue', true),
188-
)
189-
}
190-
}
191142
if (opts.strategy) {
192-
// one provider only
193143
providers.push(
194144
MockProvider(MetadataRouteStrategy, opts.strategy, 'useValue'),
195145
)
196146
}
197-
if (opts.strategies === undefined && opts.strategy === undefined) {
198-
// default: one of many providers
199-
providers.push(
200-
MockProvider(
201-
MetadataRouteStrategy,
202-
MockService(MetadataRouteStrategy),
203-
'useValue',
204-
true,
205-
),
206-
)
207-
}
208147

209148
TestBed.configureTestingModule({
210149
providers,

projects/ngx-meta/src/routing/src/router-listener.service.ts

Lines changed: 8 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,18 @@ import { MetadataRouteStrategy } from './metadata-route-strategy'
77
export class RouterListenerService implements OnDestroy {
88
// Replace by `takeUntilDestroyed` when stable
99
// https://angular.io/api/core/rxjs-interop/takeUntilDestroyed
10-
private subscription?: Subscription
10+
private sub?: Subscription
1111

1212
constructor(
1313
private readonly router: Router,
1414
private readonly activatedRoute: ActivatedRoute,
1515
@Optional()
1616
@Inject(MetadataRouteStrategy)
17-
private readonly metadataRouteStrategies: ReadonlyArray<MetadataRouteStrategy>,
17+
private readonly strategy: MetadataRouteStrategy | null,
1818
) {}
1919

2020
public listen() {
21-
if (this.isListening) {
21+
if (this.sub) {
2222
if (ngDevMode) {
2323
console.warn(
2424
'NgxMetaRoutingModule was set to listen for route changes ' +
@@ -28,38 +28,27 @@ export class RouterListenerService implements OnDestroy {
2828
return
2929
}
3030

31-
this.subscription = this.router.events
31+
this.sub = this.router.events
3232
.pipe(filter(({ type }) => type === EventType.NavigationEnd))
3333
.subscribe({
3434
next: () => {
35-
if (!this.metadataRouteStrategies) {
35+
if (!this.strategy) {
3636
if (ngDevMode) {
3737
console.warn(
3838
'`NgxMetaRoutingModule` tried to set metadata for this ' +
39-
'route but no metadata route strategies were found. ' +
39+
'route but no metadata route strategy was found. ' +
4040
'Provide at least one `MetadataRouteStrategy` to be able ' +
4141
'to resolve metadata from a route and set it in order to ' +
4242
'fix this.',
4343
)
4444
}
4545
return
4646
}
47-
const strategies = Array.isArray(this.metadataRouteStrategies)
48-
? this.metadataRouteStrategies
49-
: [this.metadataRouteStrategies]
50-
for (const strategy of strategies) {
51-
const data = strategy.resolve(this.activatedRoute.snapshot)
52-
strategy.set(data)
53-
}
47+
this.strategy.set(this.strategy.resolve(this.activatedRoute.snapshot))
5448
},
5549
})
5650
}
57-
58-
public get isListening(): boolean {
59-
return !!this.subscription
60-
}
61-
6251
ngOnDestroy(): void {
63-
this.subscription?.unsubscribe()
52+
this.sub?.unsubscribe()
6453
}
6554
}

0 commit comments

Comments
 (0)